Nhảy tới nội dung

Code

Dependencies

  • device_info_plus
  • firebase_messaging
  • flutter_local_notifications
  • http

Code triển khai

fcm_services.dart
import 'dart:io';

import 'package:device_info_plus/device_info_plus.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

import 'local_notitfication_helper.dart';
import 'package:http/http.dart' as http;

class FCMService {
FCMService._();

static FCMService? _instance;

static FCMService get instance {
return _instance ??= FCMService._();
}

final FirebaseMessaging _messaging = FirebaseMessaging.instance;

/// FCM Token
Future<String> _getFCMToken() async {
return await _messaging.getToken() ?? '';
}

/// APN Token IOS -> dùng khi muốn gửi noti trực tiếp qua APNs mà không dùng FCM
Future<String> _getAPNToken() async {
await FirebaseMessaging.instance.requestPermission();
return await _messaging.getAPNSToken() ?? '';
}

Future<String> getFCMRegistrationToken() async {
final token = await _getFCMToken();
if (kDebugMode) {
print('FCM RegistrationToken: $token');
}
return token;
}

/// Call in main.dart to init FCM
Future<void> init() async {
LocalNotificationHelper.instance.init();
_listenMessageOnForeground();
_listenMessageOnBackground();
}

void _listenMessageOnForeground() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
final RemoteNotification? notification = message.notification;

if (notification != null) {
showLocalNotification(notification);
}
});
}

void showLocalNotification(RemoteNotification notification) async {
// Đặt id cho thông báo (nếu có)
final notificationId = LocalNotificationHelper.generalNotificationId;
final notificationTitle = notification.title;
final notificationBody = notification.body;
final notificationImageUrl =
notification.android?.imageUrl ?? notification.apple?.imageUrl;

BigPictureStyleInformation? bigPictureStyleInformation;

if (notificationImageUrl != null) {
final Uint8List? bitmap = await _getBytesFromUrl(notificationImageUrl);
if (bitmap != null) {
final bigPicture = ByteArrayAndroidBitmap(bitmap);
bigPictureStyleInformation = BigPictureStyleInformation(
bigPicture,
);
}
}

final androidNotificationDetails = AndroidNotificationDetails(
LocalNotificationHelper.generalNotificationChannelId,
LocalNotificationHelper.generalNotificationChannelName,
importance: Importance.defaultImportance,
priority: Priority.high,
styleInformation: bigPictureStyleInformation,
);
final generalNotificationDetails = NotificationDetails(
android: androidNotificationDetails,
);

LocalNotificationHelper.instance.showNotification(
notificationId,
notificationTitle,
notificationBody,
notificationDetails: generalNotificationDetails,
);
}

void _listenMessageOnBackground() {
FirebaseMessaging.onBackgroundMessage(onBackgroundMessage);
}

static Future<void> onBackgroundMessage(RemoteMessage message) async {
final notification = message.notification;

if (notification != null) {
// Todo: Tuỳ chỉnh nếu cần
// FCMService.instance.showLocalNotification(notification);
}
}

Future<Uint8List?> _getBytesFromUrl(String url) async {
final uri = Uri.tryParse(url);
if (uri == null) {
return null;
}
final response = await http.get(uri);
return response.bodyBytes;
}

/// Device Id
Future<String?> getDeviceId() async {
final deviceInfoPlugin = DeviceInfoPlugin();
if (Platform.isAndroid) {
final AndroidDeviceInfo androidInfo = await deviceInfoPlugin.androidInfo;
return androidInfo.id;
} else if (Platform.isIOS) {
final IosDeviceInfo iosInfo = await deviceInfoPlugin.iosInfo;
return iosInfo.identifierForVendor;
}

return null;
}
}

local_notification_helper.dart
import 'package:flutter_local_notifications/flutter_local_notifications.dart';

/// [LocalNotificationHelper] handle show local notification
///
class LocalNotificationHelper {
LocalNotificationHelper._();

static LocalNotificationHelper? _instance;

static LocalNotificationHelper get instance {
return _instance ??= LocalNotificationHelper._();
}

static const String generalNotificationChannelId = 'id-general-notifications';
static const String generalNotificationChannelName = 'General notifications';
static const int generalNotificationId = 321;

final FlutterLocalNotificationsPlugin _notificationsPlugin =
FlutterLocalNotificationsPlugin();

('vm:entry-point')
static Function(NotificationResponse notificationResponse)?
onDidReceiveBackgroundNotificationResponse;

void init({
Function(NotificationResponse notificationResponse)?
onDidReceiveNotificationResponse,
}) async {
final AndroidInitializationSettings initializationSettingsAndroid =
AndroidInitializationSettings('@mipmap/ic_launcher');
final DarwinInitializationSettings initializationSettingsDarwin =
DarwinInitializationSettings();

final InitializationSettings initializationSettings =
InitializationSettings(
android: initializationSettingsAndroid,
iOS: initializationSettingsDarwin,
);

await _notificationsPlugin.initialize(
initializationSettings,
onDidReceiveNotificationResponse: onDidReceiveNotificationResponse,
onDidReceiveBackgroundNotificationResponse:
onDidReceiveBackgroundNotificationResponse,
);
}

Future<void> showNotification(int id,
String? title,
String? body, {
NotificationDetails? notificationDetails,
String? payload,
}) async {
final AndroidNotificationDetails androidNotificationDetails =
AndroidNotificationDetails(
generalNotificationChannelId,
generalNotificationChannelName,
importance: Importance.defaultImportance,
priority: Priority.high,
);
final generalNotificationDetails = NotificationDetails(
android: androidNotificationDetails,
);

await _notificationsPlugin.show(
id,
title,
body,
notificationDetails ?? generalNotificationDetails,
);
}
}

Sử dụng

  • Gọi FCMService.instance.init() trong main.dart
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);

await FCMService.instance.init();

runApp(const MyApp());
}