setup fcm
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
@module
|
||||
abstract class FirebaseDi {
|
||||
@lazySingleton
|
||||
FirebaseMessaging get messaging => FirebaseMessaging.instance;
|
||||
|
||||
@lazySingleton
|
||||
FlutterLocalNotificationsPlugin get localNotifications =>
|
||||
FlutterLocalNotificationsPlugin();
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
// CONTOH PENGGUNAAN FCM SERVICE
|
||||
// File ini hanya untuk referensi, tidak perlu diimport ke app
|
||||
|
||||
import 'package:apskel_pos_flutter_v2/common/service/fcm_service.dart';
|
||||
import 'package:apskel_pos_flutter_v2/injection.dart';
|
||||
|
||||
/// Contoh 1: Ambil FCM token
|
||||
Future<void> exampleGetToken() async {
|
||||
final fcmService = getIt<FcmService>();
|
||||
final token = await fcmService.getToken();
|
||||
print('FCM Token: $token');
|
||||
|
||||
// Kirim token ke server untuk push notification
|
||||
// await apiClient.sendTokenToServer(token);
|
||||
}
|
||||
|
||||
/// Contoh 2: Subscribe ke topic
|
||||
Future<void> exampleSubscribeToTopic() async {
|
||||
final fcmService = getIt<FcmService>();
|
||||
|
||||
// Subscribe ke topic "all_users"
|
||||
await fcmService.subscribeToTopic('all_users');
|
||||
|
||||
// Subscribe ke topic berdasarkan outlet_id
|
||||
await fcmService.subscribeToTopic('outlet_123');
|
||||
}
|
||||
|
||||
/// Contoh 3: Unsubscribe dari topic
|
||||
Future<void> exampleUnsubscribeFromTopic() async {
|
||||
final fcmService = getIt<FcmService>();
|
||||
|
||||
await fcmService.unsubscribeFromTopic('outlet_123');
|
||||
}
|
||||
|
||||
/// Contoh 4: Gunakan di BLoC
|
||||
///
|
||||
/// class NotificationBloc extends Bloc<NotificationEvent, NotificationState> {
|
||||
/// final FcmService _fcmService;
|
||||
///
|
||||
/// NotificationBloc(this._fcmService) : super(NotificationInitial()) {
|
||||
/// on<GetFcmToken>(_onGetFcmToken);
|
||||
/// on<SubscribeToTopic>(_onSubscribeToTopic);
|
||||
/// }
|
||||
///
|
||||
/// Future<void> _onGetFcmToken(
|
||||
/// GetFcmToken event,
|
||||
/// Emitter<NotificationState> emit,
|
||||
/// ) async {
|
||||
/// final token = await _fcmService.getToken();
|
||||
/// emit(NotificationTokenLoaded(token));
|
||||
/// }
|
||||
///
|
||||
/// Future<void> _onSubscribeToTopic(
|
||||
/// SubscribeToTopic event,
|
||||
/// Emitter<NotificationState> emit,
|
||||
/// ) async {
|
||||
/// await _fcmService.subscribeToTopic(event.topic);
|
||||
/// emit(NotificationTopicSubscribed(event.topic));
|
||||
/// }
|
||||
/// }
|
||||
|
||||
/// Contoh 5: Gunakan di Repository
|
||||
///
|
||||
/// @LazySingleton(as: IAuthRepository)
|
||||
/// class AuthRepository implements IAuthRepository {
|
||||
/// final FcmService _fcmService;
|
||||
/// final ApiClient _apiClient;
|
||||
///
|
||||
/// AuthRepository(this._fcmService, this._apiClient);
|
||||
///
|
||||
/// @override
|
||||
/// Future<Either<Failure, User>> login(String email, String password) async {
|
||||
/// try {
|
||||
/// final response = await _apiClient.login(email, password);
|
||||
///
|
||||
/// // Kirim FCM token ke server setelah login berhasil
|
||||
/// final fcmToken = await _fcmService.getToken();
|
||||
/// if (fcmToken != null) {
|
||||
/// await _apiClient.updateFcmToken(fcmToken);
|
||||
/// }
|
||||
///
|
||||
/// return Right(response);
|
||||
/// } catch (e) {
|
||||
/// return Left(ServerFailure(e.toString()));
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
@@ -0,0 +1,191 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
/// Background message handler — harus top-level function
|
||||
@pragma('vm:entry-point')
|
||||
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
log('[FCM] Background message: ${message.messageId}');
|
||||
}
|
||||
|
||||
@lazySingleton
|
||||
class FcmService {
|
||||
FcmService(this._messaging, this._localNotifications);
|
||||
|
||||
final FirebaseMessaging _messaging;
|
||||
final FlutterLocalNotificationsPlugin _localNotifications;
|
||||
|
||||
/// Inisialisasi FCM: minta permission, set handler, ambil token
|
||||
Future<void> initialize() async {
|
||||
// Setup local notifications
|
||||
await _setupLocalNotifications();
|
||||
|
||||
// Register background handler
|
||||
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
||||
|
||||
// Minta permission notifikasi (iOS & Android 13+)
|
||||
final settings = await _messaging.requestPermission(
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true,
|
||||
provisional: false,
|
||||
);
|
||||
|
||||
log('[FCM] Permission status: ${settings.authorizationStatus}');
|
||||
|
||||
if (settings.authorizationStatus == AuthorizationStatus.authorized ||
|
||||
settings.authorizationStatus == AuthorizationStatus.provisional) {
|
||||
await _setupTokenHandling();
|
||||
_setupForegroundHandler();
|
||||
_setupOpenedAppHandler();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _setupLocalNotifications() async {
|
||||
const androidSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||
const iosSettings = DarwinInitializationSettings(
|
||||
requestAlertPermission: true,
|
||||
requestBadgePermission: true,
|
||||
requestSoundPermission: true,
|
||||
);
|
||||
|
||||
const initSettings = InitializationSettings(
|
||||
android: androidSettings,
|
||||
iOS: iosSettings,
|
||||
);
|
||||
|
||||
await _localNotifications.initialize(
|
||||
initSettings,
|
||||
onDidReceiveNotificationResponse: _onNotificationTapped,
|
||||
);
|
||||
|
||||
// Android notification channel
|
||||
const channel = AndroidNotificationChannel(
|
||||
'high_importance_channel',
|
||||
'High Importance Notifications',
|
||||
description: 'This channel is used for important notifications.',
|
||||
importance: Importance.high,
|
||||
);
|
||||
|
||||
await _localNotifications
|
||||
.resolvePlatformSpecificImplementation<
|
||||
AndroidFlutterLocalNotificationsPlugin>()
|
||||
?.createNotificationChannel(channel);
|
||||
}
|
||||
|
||||
void _onNotificationTapped(NotificationResponse response) {
|
||||
log('[FCM] Notification tapped: ${response.payload}');
|
||||
// TODO: handle navigation berdasarkan payload
|
||||
}
|
||||
|
||||
Future<void> _setupTokenHandling() async {
|
||||
final token = await getToken();
|
||||
log('========================================');
|
||||
log('[FCM] TOKEN: $token');
|
||||
log('========================================');
|
||||
// TODO: kirim token ke server jika diperlukan
|
||||
|
||||
_messaging.onTokenRefresh.listen((newToken) {
|
||||
log('========================================');
|
||||
log('[FCM] TOKEN REFRESHED: $newToken');
|
||||
log('========================================');
|
||||
// TODO: kirim token baru ke server jika diperlukan
|
||||
});
|
||||
}
|
||||
|
||||
void _setupForegroundHandler() {
|
||||
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
||||
log('[FCM] Foreground message: ${message.messageId}');
|
||||
log('[FCM] Title: ${message.notification?.title}');
|
||||
log('[FCM] Body: ${message.notification?.body}');
|
||||
log('[FCM] Data: ${message.data}');
|
||||
|
||||
// Tampilkan notifikasi lokal saat app di foreground
|
||||
final notification = message.notification;
|
||||
if (notification != null) {
|
||||
_showLocalNotification(
|
||||
id: message.hashCode,
|
||||
title: notification.title ?? '',
|
||||
body: notification.body ?? '',
|
||||
payload: message.data.toString(),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void _setupOpenedAppHandler() {
|
||||
// App dibuka dari notifikasi saat terminated
|
||||
_messaging.getInitialMessage().then((RemoteMessage? message) {
|
||||
if (message != null) {
|
||||
log('[FCM] App opened from terminated via: ${message.messageId}');
|
||||
_handleMessageNavigation(message);
|
||||
}
|
||||
});
|
||||
|
||||
// App dibuka dari notifikasi saat background
|
||||
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
|
||||
log('[FCM] App opened from background via: ${message.messageId}');
|
||||
_handleMessageNavigation(message);
|
||||
});
|
||||
}
|
||||
|
||||
void _handleMessageNavigation(RemoteMessage message) {
|
||||
// TODO: tambahkan logika navigasi berdasarkan message.data
|
||||
log('[FCM] Handle navigation for: ${message.data}');
|
||||
}
|
||||
|
||||
Future<void> _showLocalNotification({
|
||||
required int id,
|
||||
required String title,
|
||||
required String body,
|
||||
String? payload,
|
||||
}) async {
|
||||
const androidDetails = AndroidNotificationDetails(
|
||||
'high_importance_channel',
|
||||
'High Importance Notifications',
|
||||
channelDescription: 'This channel is used for important notifications.',
|
||||
importance: Importance.high,
|
||||
priority: Priority.high,
|
||||
showWhen: true,
|
||||
icon: 'ic_notification',
|
||||
);
|
||||
|
||||
const iosDetails = DarwinNotificationDetails(
|
||||
presentAlert: true,
|
||||
presentBadge: true,
|
||||
presentSound: true,
|
||||
);
|
||||
|
||||
const details = NotificationDetails(
|
||||
android: androidDetails,
|
||||
iOS: iosDetails,
|
||||
);
|
||||
|
||||
await _localNotifications.show(id, title, body, details, payload: payload);
|
||||
log('[FCM] Local notification shown: $title');
|
||||
}
|
||||
|
||||
/// Ambil FCM token perangkat
|
||||
Future<String?> getToken() async {
|
||||
try {
|
||||
return await _messaging.getToken();
|
||||
} catch (e) {
|
||||
log('[FCM] Failed to get token: $e');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// Subscribe ke topic tertentu
|
||||
Future<void> subscribeToTopic(String topic) async {
|
||||
await _messaging.subscribeToTopic(topic);
|
||||
log('[FCM] Subscribed to topic: $topic');
|
||||
}
|
||||
|
||||
/// Unsubscribe dari topic tertentu
|
||||
Future<void> unsubscribeFromTopic(String topic) async {
|
||||
await _messaging.unsubscribeFromTopic(topic);
|
||||
log('[FCM] Unsubscribed from topic: $topic');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user