Update alarm notification when app in foreground, background and terminate
This commit is contained in:
@@ -8,7 +8,9 @@ import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:badges/badges.dart' as badges;
|
||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
||||
import 'package:sfm_app/product/shared/shared_snack_bar.dart';
|
||||
|
||||
import '../../product/services/notification_services.dart';
|
||||
import '../../product/utils/permission_handler.dart';
|
||||
import '../../product/permission/notification_permission.dart';
|
||||
import '../settings/profile/profile_model.dart';
|
||||
@@ -43,20 +45,10 @@ class MainScreen extends StatefulWidget {
|
||||
State<MainScreen> createState() => _MainScreenState();
|
||||
}
|
||||
|
||||
// @pragma('vm:entry-point')
|
||||
// Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
// log("Full background message payload: ${message.toMap()}");
|
||||
// await Firebase.initializeApp();
|
||||
// final notificationServices = NotificationServices();
|
||||
// await notificationServices.initLocalNotifications(controller);
|
||||
// await notificationServices.showNotification(message);
|
||||
// log("Background message handled: ${message.data['title']}");
|
||||
// }
|
||||
|
||||
class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
|
||||
PersistentTabController controller = PersistentTabController(initialIndex: 0);
|
||||
|
||||
APIServices apiServices = APIServices();
|
||||
// final NotificationServices notificationServices = NotificationServices();
|
||||
final NotificationServices notificationServices = NotificationServices();
|
||||
late MainBloc mainBloc;
|
||||
bool isVN = true;
|
||||
bool isLight = true;
|
||||
@@ -84,7 +76,12 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
|
||||
mainBloc.sinkIsVNIcon.add(isVN);
|
||||
mainBloc.sinkThemeMode.add(isLight);
|
||||
checkAndRequestPermission();
|
||||
NotificationServices.requestNotificationPermission();
|
||||
NotificationPermission.instance.checkNotificationPermission(context);
|
||||
bool? notificationStatus = await NotificationPermission.instance.requestNotificationPermission();
|
||||
if(!notificationStatus!){
|
||||
showNoIconTopSnackBar(context, "Yêu cầu quyền thông báo không thành công", Colors.orange, Colors.white12);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -103,44 +100,11 @@ class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
|
||||
mainBloc.sendNotificationToken(newToken);
|
||||
});
|
||||
|
||||
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
|
||||
RemoteNotification? notification = message.notification;
|
||||
AndroidNotification? android = message.notification?.android;
|
||||
if (notification != null && android != null) {
|
||||
const AndroidNotificationDetails androidPlatformChannelSpecifics =
|
||||
AndroidNotificationDetails('your channel id', 'your channel name',
|
||||
importance: Importance.max,
|
||||
priority: Priority.high,
|
||||
ticker: 'ticker');
|
||||
const NotificationDetails platformChannelSpecifics =
|
||||
NotificationDetails(android: androidPlatformChannelSpecifics);
|
||||
flutterLocalNotificationsPlugin.show(
|
||||
notification.hashCode,
|
||||
notification.title,
|
||||
notification.body,
|
||||
platformChannelSpecifics,
|
||||
);
|
||||
}
|
||||
});
|
||||
// notificationServices.initLocalNotifications(controller);
|
||||
// notificationServices.firebaseInit(context);
|
||||
// NotificationServices().setupInteractMessage(controller);
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
super.didChangeAppLifecycleState(state);
|
||||
if (state == AppLifecycleState.inactive) {
|
||||
log("App Inactive");
|
||||
} else if (state == AppLifecycleState.resumed) {
|
||||
log("App Resumed");
|
||||
} else if (state == AppLifecycleState.paused) {
|
||||
log("App paused");
|
||||
} else if (state == AppLifecycleState.detached) {
|
||||
log("App detached");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
|
||||
103
lib/main.dart
103
lib/main.dart
@@ -1,12 +1,12 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:alarm/alarm.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'firebase_options.dart';
|
||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart' show PersistentTabController;
|
||||
|
||||
import 'firebase_options.dart';
|
||||
import 'product/lang/l10n/app_localizations.dart';
|
||||
import 'product/services/api_services.dart';
|
||||
import 'product/services/notification_services.dart';
|
||||
@@ -16,88 +16,16 @@ import 'bloc/main_bloc.dart';
|
||||
import 'product/base/bloc/base_bloc.dart';
|
||||
import 'product/constant/navigation/navigation_router.dart';
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
|
||||
await setupFlutterNotifications();
|
||||
showFlutterNotification(message);
|
||||
print('Handling a background message ${message.messageId}');
|
||||
}
|
||||
|
||||
|
||||
/// Create a [AndroidNotificationChannel] for heads up notifications
|
||||
late AndroidNotificationChannel channel;
|
||||
PersistentTabController controller = PersistentTabController(initialIndex: 0);
|
||||
|
||||
bool isFlutterLocalNotificationsInitialized = false;
|
||||
|
||||
Future<void> setupFlutterNotifications() async {
|
||||
if (isFlutterLocalNotificationsInitialized) {
|
||||
return;
|
||||
}
|
||||
channel = const AndroidNotificationChannel(
|
||||
'high_importance_channel', // id
|
||||
'High Importance Notifications', // title
|
||||
description:
|
||||
'This channel is used for important notifications.', // description
|
||||
importance: Importance.high,
|
||||
);
|
||||
|
||||
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
||||
|
||||
/// Create an Android Notification Channel.
|
||||
///
|
||||
/// We use this channel in the `AndroidManifest.xml` file to override the
|
||||
/// default FCM channel to enable heads up notifications.
|
||||
await flutterLocalNotificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<
|
||||
AndroidFlutterLocalNotificationsPlugin>()
|
||||
?.createNotificationChannel(channel);
|
||||
|
||||
/// Update the iOS foreground notification presentation options to allow
|
||||
/// heads up notifications.
|
||||
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
|
||||
alert: true,
|
||||
badge: true,
|
||||
sound: true,
|
||||
);
|
||||
isFlutterLocalNotificationsInitialized = true;
|
||||
}
|
||||
|
||||
void showFlutterNotification(RemoteMessage message) {
|
||||
RemoteNotification? notification = message.notification;
|
||||
AndroidNotification? android = message.notification?.android;
|
||||
if (notification != null && android != null && !kIsWeb) {
|
||||
flutterLocalNotificationsPlugin.show(
|
||||
notification.hashCode,
|
||||
notification.title,
|
||||
notification.body,
|
||||
NotificationDetails(
|
||||
android: AndroidNotificationDetails(
|
||||
channel.id,
|
||||
channel.name,
|
||||
channelDescription: channel.description,
|
||||
// TODO add a proper drawable resource to android, for now using
|
||||
// one that already exists in example app.
|
||||
icon: 'launch_background',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize the [FlutterLocalNotificationsPlugin] package.
|
||||
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Firebase.initializeApp();
|
||||
// Set the background messaging handler early on, as a named top-level function
|
||||
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
|
||||
|
||||
if (!kIsWeb) {
|
||||
await setupFlutterNotifications();
|
||||
}
|
||||
|
||||
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform, name: "sfm-notification");
|
||||
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
|
||||
await Alarm.init();
|
||||
runApp(
|
||||
BlocProvider(
|
||||
child: const MyApp(),
|
||||
@@ -129,7 +57,7 @@ class _MyAppState extends State<MyApp> {
|
||||
late MainBloc mainBloc;
|
||||
LanguageServices languageServices = LanguageServices();
|
||||
ThemeServices themeServices = ThemeServices();
|
||||
// final NotificationServices notificationServices = NotificationServices();
|
||||
final NotificationServices notificationServices = NotificationServices();
|
||||
APIServices apiServices = APIServices();
|
||||
setLocale(Locale locale) {
|
||||
_locale = locale;
|
||||
@@ -145,20 +73,11 @@ class _MyAppState extends State<MyApp> {
|
||||
void initState() {
|
||||
super.initState();
|
||||
mainBloc = BlocProvider.of(context);
|
||||
// // notificationServices.initLocalNotifications();
|
||||
// // notificationServices.firebaseInit(context);
|
||||
// // notificationServices.setupInteractMessage();
|
||||
// notificationServices.getDeviceToken().then((token){
|
||||
// log("Firebase Token: $token");
|
||||
// sendNotificationToken(token);
|
||||
// });
|
||||
notificationServices.initialize();
|
||||
notificationServices.firebaseInit(context);
|
||||
notificationServices.setupInteractMessage(controller);
|
||||
}
|
||||
|
||||
// void sendNotificationToken (String token) async {
|
||||
// int statusCode = await apiServices.sendNotificationToken(token);
|
||||
// log("Notification Send StatusCode : $statusCode");
|
||||
// }
|
||||
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
languageServices.getLocale().then((locale) => {setLocale(locale)});
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:app_settings/app_settings.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import '../base/widget/dialog/request_permission_dialog.dart';
|
||||
|
||||
@@ -11,7 +13,7 @@ class NotificationPermission {
|
||||
static NotificationPermission? _instance;
|
||||
static NotificationPermission get instance =>
|
||||
_instance ??= NotificationPermission._init();
|
||||
|
||||
static final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin();
|
||||
Future<bool> checkNotificationPermission(context) async {
|
||||
var status = await Permission.notification.status;
|
||||
log("Status: $status");
|
||||
@@ -44,4 +46,21 @@ class NotificationPermission {
|
||||
Icons.location_on_outlined, "ABCDE", AppSettingsType.notification);
|
||||
}
|
||||
}
|
||||
Future<bool?> requestNotificationPermission() async {
|
||||
try {
|
||||
if (Platform.isAndroid) {
|
||||
return await _notificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
|
||||
?.requestNotificationsPermission();
|
||||
} else if (Platform.isIOS) {
|
||||
return await _notificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()
|
||||
?.requestPermissions(alert: true, sound: true, badge: true);
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
log("Error requesting notification permission: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
34
lib/product/services/alarm_services.dart
Normal file
34
lib/product/services/alarm_services.dart
Normal file
@@ -0,0 +1,34 @@
|
||||
import 'dart:io';
|
||||
import 'package:alarm/alarm.dart';
|
||||
|
||||
class AlarmServices {
|
||||
Future<void> showAlarm(String title, String body) async {
|
||||
final DateTime now = DateTime.now();
|
||||
final AlarmSettings alarmSettings = AlarmSettings(
|
||||
id: 42,
|
||||
dateTime: now,
|
||||
assetAudioPath: 'assets/sounds/warning_alarm.mp3',
|
||||
loopAudio: true,
|
||||
vibrate: true,
|
||||
warningNotificationOnKill: Platform.isIOS,
|
||||
androidFullScreenIntent: true,
|
||||
allowAlarmOverlap: true,
|
||||
volumeSettings: VolumeSettings.fade(
|
||||
volume: 1.0,
|
||||
fadeDuration: const Duration(seconds: 3),
|
||||
volumeEnforced: true,
|
||||
),
|
||||
notificationSettings: NotificationSettings(
|
||||
title: title,
|
||||
body: body,
|
||||
stopButton: 'Dừng cảnh báo',
|
||||
icon: 'ic_launcher',
|
||||
),
|
||||
);
|
||||
await Alarm.set(alarmSettings: alarmSettings);
|
||||
}
|
||||
|
||||
void cancelAlarm({int id = 42}) async {
|
||||
await Alarm.stop(id);
|
||||
}
|
||||
}
|
||||
@@ -1,117 +1,162 @@
|
||||
import 'dart:developer' as dev;
|
||||
import 'dart:io';
|
||||
import 'dart:math' as math;
|
||||
import 'package:firebase_messaging/firebase_messaging.dart';
|
||||
import 'package:alarm/alarm.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:firebase_messaging/firebase_messaging.dart' hide NotificationSettings;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||
import 'package:persistent_bottom_nav_bar_v2/persistent_bottom_nav_bar_v2.dart';
|
||||
import 'package:sfm_app/product/utils/app_logger_utils.dart';
|
||||
|
||||
import '../../firebase_options.dart';
|
||||
import '../../main.dart';
|
||||
import 'alarm_services.dart';
|
||||
|
||||
class NotificationServices {
|
||||
FirebaseMessaging messaging = FirebaseMessaging.instance;
|
||||
final FlutterLocalNotificationsPlugin _flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
|
||||
static final FlutterLocalNotificationsPlugin _notificationsPlugin = FlutterLocalNotificationsPlugin();
|
||||
final FirebaseMessaging _messaging = FirebaseMessaging.instance;
|
||||
AlarmServices alarmServices = AlarmServices();
|
||||
|
||||
Future<void> initLocalNotifications(PersistentTabController controller) async {
|
||||
const AndroidInitializationSettings androidInitializationSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||
const DarwinInitializationSettings iosInitializationSettings = DarwinInitializationSettings();
|
||||
const InitializationSettings initializationSettings = InitializationSettings(
|
||||
android: androidInitializationSettings,
|
||||
iOS: iosInitializationSettings,
|
||||
);
|
||||
Future<void> initialize() async {
|
||||
await initializeLocalNotifications();
|
||||
dev.log("NotificationService initialized");
|
||||
}
|
||||
|
||||
await _flutterLocalNotificationsPlugin.initialize(
|
||||
initializationSettings,
|
||||
onDidReceiveNotificationResponse: (NotificationResponse response) {
|
||||
dev.log("Người dùng click thông báo ở foreground với payload: ${response.payload}");
|
||||
handleMessage(response.payload,controller);
|
||||
},
|
||||
);
|
||||
dev.log("Local notifications initialized");
|
||||
Future<void> initializeLocalNotifications() async {
|
||||
try{
|
||||
const AndroidInitializationSettings androidInitializationSettings = AndroidInitializationSettings('@mipmap/ic_launcher');
|
||||
const DarwinInitializationSettings iosInitializationSettings = DarwinInitializationSettings();
|
||||
const InitializationSettings initializationSettings = InitializationSettings(
|
||||
android: androidInitializationSettings,
|
||||
iOS: iosInitializationSettings,
|
||||
);
|
||||
|
||||
await _notificationsPlugin.initialize(
|
||||
initializationSettings,
|
||||
onDidReceiveNotificationResponse: (NotificationResponse response) {
|
||||
dev.log("Người dùng click thông báo ở foreground với payload: ${response.payload}");
|
||||
handleMessage(response.payload,controller);
|
||||
},
|
||||
);
|
||||
dev.log("Local notifications initialized");
|
||||
}catch(e){
|
||||
dev.log("Error initializing local notifications: $e");
|
||||
}
|
||||
}
|
||||
|
||||
void firebaseInit(BuildContext context) {
|
||||
FirebaseMessaging.onMessage.listen((message) {
|
||||
dev.log("Foreground message payload: ${message.toMap()}");
|
||||
showNotification(message);
|
||||
});
|
||||
}
|
||||
|
||||
Future<String> getDeviceToken() async {
|
||||
print("GET FB TOKEN");
|
||||
String? token = await messaging.getToken();
|
||||
print("GET FB: ${token}");
|
||||
return token!;
|
||||
_showNotification(message);
|
||||
});
|
||||
}
|
||||
|
||||
void isTokenRefresh() {
|
||||
messaging.onTokenRefresh.listen((newToken) {
|
||||
_messaging.onTokenRefresh.listen((newToken) {
|
||||
dev.log("Refresh Firebase Messaging Token: $newToken");
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> showNotification(RemoteMessage message) async {
|
||||
dev.log(message.toString());
|
||||
dev.log(message.data.toString());
|
||||
dev.log(message.data["notification"].toString());
|
||||
String? title = message.data['title'];
|
||||
String? body = message.data['body'];
|
||||
String type = message.data['type'] ?? "normal";
|
||||
|
||||
if (title == null || body == null) {
|
||||
dev.log("Skipping notification due to missing title or body");
|
||||
return;
|
||||
static Future<bool?> requestNotificationPermission() async {
|
||||
try {
|
||||
if (Platform.isAndroid) {
|
||||
return await _notificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>()
|
||||
?.requestNotificationsPermission();
|
||||
} else if (Platform.isIOS) {
|
||||
return await _notificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<IOSFlutterLocalNotificationsPlugin>()
|
||||
?.requestPermissions(alert: true, sound: true, badge: true);
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
dev.log("Error requesting notification permission: $e");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
AndroidNotificationChannel androidNotificationChannel = AndroidNotificationChannel(
|
||||
math.Random.secure().nextInt(1000000).toString(),
|
||||
'High Importance Notification',
|
||||
importance: Importance.max,
|
||||
);
|
||||
Future<void> _showNotification(RemoteMessage message) async {
|
||||
try {
|
||||
// Early validation of notification data
|
||||
final title = message.data['title'] as String?;
|
||||
final body = message.data['body'] as String?;
|
||||
final type = message.data['type'] as String? ?? 'normal';
|
||||
|
||||
final androidPlugin = _flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>();
|
||||
await androidPlugin?.deleteNotificationChannel(androidNotificationChannel.id);
|
||||
if (title == null || body == null) {
|
||||
dev.log('Skipping notification: missing title or body', name: 'Notification');
|
||||
return;
|
||||
}
|
||||
|
||||
AndroidNotificationDetails androidNotificationDetails = AndroidNotificationDetails(
|
||||
androidNotificationChannel.id,
|
||||
androidNotificationChannel.name,
|
||||
channelDescription: "Channel description",
|
||||
sound: getSound(type),
|
||||
importance: androidNotificationChannel.importance,
|
||||
priority: Priority.high,
|
||||
ticker: 'ticker',
|
||||
actions: type == "smoke_warning"
|
||||
? [
|
||||
const AndroidNotificationAction(
|
||||
"id1",
|
||||
"Hogg xóa được",
|
||||
// true thì khi nhấn vào button sẽ mở giao diện ra
|
||||
showsUserInterface: true,
|
||||
cancelNotification: false,
|
||||
)
|
||||
]
|
||||
: null
|
||||
);
|
||||
// Handle smoke warning notifications
|
||||
if (type == 'smoke_warning') {
|
||||
await alarmServices.showAlarm(title, body);
|
||||
dev.log('Displayed smoke warning notification', name: 'Notification');
|
||||
return;
|
||||
}
|
||||
|
||||
const DarwinNotificationDetails darwinNotificationDetails = DarwinNotificationDetails(
|
||||
presentAlert: true,
|
||||
presentBadge: true,
|
||||
presentBanner: true,
|
||||
presentSound: true,
|
||||
);
|
||||
// Create notification channel
|
||||
final channelId = math.Random.secure().nextInt(1000000).toString();
|
||||
const channelName = 'High Importance Notification';
|
||||
const channelDescription = 'Channel description';
|
||||
|
||||
NotificationDetails notificationDetails = NotificationDetails(
|
||||
android: androidNotificationDetails,
|
||||
iOS: darwinNotificationDetails,
|
||||
);
|
||||
final androidChannel = AndroidNotificationChannel(
|
||||
channelId,
|
||||
channelName,
|
||||
importance: Importance.max,
|
||||
description: channelDescription,
|
||||
);
|
||||
|
||||
// Truyền payload vào thông báo
|
||||
String payload = message.data['type'] ?? "default";
|
||||
await _flutterLocalNotificationsPlugin.show(
|
||||
math.Random.secure().nextInt(1000000),
|
||||
title,
|
||||
body,
|
||||
notificationDetails,
|
||||
payload: payload,
|
||||
);
|
||||
dev.log("Displayed notification with title: $title, body: $body, type: $type");
|
||||
final androidPlugin = _notificationsPlugin
|
||||
.resolvePlatformSpecificImplementation<AndroidFlutterLocalNotificationsPlugin>();
|
||||
|
||||
// Delete existing channel to prevent conflicts
|
||||
await androidPlugin?.deleteNotificationChannel(channelId);
|
||||
|
||||
// Configure notification details
|
||||
final androidDetails = AndroidNotificationDetails(
|
||||
channelId,
|
||||
channelName,
|
||||
channelDescription: channelDescription,
|
||||
sound: getSound(type),
|
||||
importance: Importance.max,
|
||||
priority: Priority.high,
|
||||
ticker: 'ticker',
|
||||
);
|
||||
|
||||
const iosDetails = DarwinNotificationDetails(
|
||||
presentAlert: true,
|
||||
presentBadge: true,
|
||||
presentBanner: true,
|
||||
presentSound: true,
|
||||
);
|
||||
|
||||
final notificationDetails = NotificationDetails(
|
||||
android: androidDetails,
|
||||
iOS: iosDetails,
|
||||
);
|
||||
|
||||
// Show notification
|
||||
await _notificationsPlugin.show(
|
||||
int.parse(channelId),
|
||||
title,
|
||||
body,
|
||||
notificationDetails,
|
||||
payload: type,
|
||||
);
|
||||
|
||||
dev.log(
|
||||
'Displayed notification - title: $title, body: $body, type: $type',
|
||||
name: 'Notification',
|
||||
);
|
||||
} catch (e, stackTrace) {
|
||||
dev.log(
|
||||
'Failed to show notification: $e',
|
||||
name: 'Notification',
|
||||
error: e,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AndroidNotificationSound getSound(String type) {
|
||||
@@ -155,4 +200,120 @@ class NotificationServices {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> showBackgroundOrTerminateNotification(RemoteMessage message) async {
|
||||
try {
|
||||
// Early validation of notification data
|
||||
final title = message.data['title'] as String?;
|
||||
final body = message.data['body'] as String?;
|
||||
final type = message.data['type'] as String? ?? 'normal';
|
||||
|
||||
if (title == null || body == null) {
|
||||
dev.log('Skipping notification: missing title or body', name: 'Notification');
|
||||
return;
|
||||
}
|
||||
|
||||
// Create notification channel
|
||||
final channelId = math.Random.secure().nextInt(1000000).toString();
|
||||
const channelName = 'High Importance Notification';
|
||||
const channelDescription = 'Channel description';
|
||||
|
||||
|
||||
// Configure notification details
|
||||
final androidDetails = AndroidNotificationDetails(
|
||||
channelId,
|
||||
channelName,
|
||||
channelDescription: channelDescription,
|
||||
sound: getSound(type),
|
||||
importance: Importance.max,
|
||||
priority: Priority.high,
|
||||
ticker: 'ticker',
|
||||
);
|
||||
|
||||
const iosDetails = DarwinNotificationDetails(
|
||||
presentAlert: true,
|
||||
presentBadge: true,
|
||||
presentBanner: true,
|
||||
presentSound: true,
|
||||
);
|
||||
|
||||
final notificationDetails = NotificationDetails(
|
||||
android: androidDetails,
|
||||
iOS: iosDetails,
|
||||
);
|
||||
|
||||
// Show notification
|
||||
await _notificationsPlugin.show(
|
||||
int.parse(channelId),
|
||||
title,
|
||||
body,
|
||||
notificationDetails,
|
||||
payload: type,
|
||||
);
|
||||
|
||||
dev.log(
|
||||
'Displayed notification - title: $title, body: $body, type: $type',
|
||||
name: 'Notification',
|
||||
);
|
||||
} catch (e, stackTrace) {
|
||||
dev.log(
|
||||
'Failed to show notification: $e',
|
||||
name: 'Notification',
|
||||
error: e,
|
||||
stackTrace: stackTrace,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
|
||||
try {
|
||||
AppLoggerUtils.warning("Background handler started: ${message.data}");
|
||||
await Alarm.init();
|
||||
if (Firebase.apps.isEmpty) {
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform,
|
||||
name: "sfm-notification"
|
||||
);
|
||||
AppLoggerUtils.warning("Firebase đã được khởi tạo trong background handler");
|
||||
} else {
|
||||
AppLoggerUtils.warning("Firebase đã được khởi tạo trước đó");
|
||||
}
|
||||
AppLoggerUtils.warning(message.toString());
|
||||
AppLoggerUtils.warning(message.data.toString());
|
||||
AppLoggerUtils.warning(message.data["notification"].toString());
|
||||
String? title = message.data['title'];
|
||||
String? body = message.data['body'];
|
||||
String type = message.data['type'] ?? "normal";
|
||||
final notificationService = NotificationServices();
|
||||
await notificationService.initialize();
|
||||
final alarmSettings = AlarmSettings(
|
||||
id: 42,
|
||||
dateTime: DateTime.now(),
|
||||
assetAudioPath: 'assets/sounds/warning_alarm.mp3',
|
||||
loopAudio: true,
|
||||
vibrate: true,
|
||||
warningNotificationOnKill: Platform.isIOS,
|
||||
androidFullScreenIntent: true,
|
||||
volumeSettings: VolumeSettings.fade(
|
||||
volume: 0.8,
|
||||
fadeDuration: const Duration(seconds: 5),
|
||||
volumeEnforced: true,
|
||||
),
|
||||
notificationSettings: NotificationSettings(
|
||||
title: title ?? "SFM",
|
||||
body: body ?? "",
|
||||
stopButton: 'Dừng thông báo',
|
||||
icon: "ic_launcher",
|
||||
),
|
||||
);
|
||||
if (type == "smoke_warning") {
|
||||
await Alarm.set(alarmSettings: alarmSettings);
|
||||
} else {
|
||||
await notificationService.showBackgroundOrTerminateNotification(message);
|
||||
}
|
||||
} catch (e) {
|
||||
AppLoggerUtils.warning("Error in background handler: $e");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user