setup fcm

This commit is contained in:
Efril
2026-05-07 17:44:03 +07:00
parent cdc65f8f8f
commit dc09aabbe8
15 changed files with 425 additions and 1 deletions
+13
View File
@@ -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();
}
+87
View File
@@ -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()));
/// }
/// }
/// }
+191
View File
@@ -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');
}
}