2023-03-28 06:36:10 +00:00
|
|
|
import 'dart:io';
|
|
|
|
|
|
|
|
|
|
import 'package:firebase_core/firebase_core.dart';
|
|
|
|
|
import 'package:firebase_messaging/firebase_messaging.dart';
|
|
|
|
|
import 'package:flutter/foundation.dart';
|
|
|
|
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
2023-10-25 10:19:17 +00:00
|
|
|
import 'package:get/get.dart';
|
2023-03-28 06:36:10 +00:00
|
|
|
|
|
|
|
|
import '../../../firebase_options.dart';
|
|
|
|
|
import '../../app.dart';
|
|
|
|
|
import 'download_file.dart';
|
|
|
|
|
|
|
|
|
|
class FCMFunctions {
|
|
|
|
|
static final FCMFunctions _singleton = new FCMFunctions._internal();
|
|
|
|
|
|
|
|
|
|
FCMFunctions._internal();
|
|
|
|
|
|
|
|
|
|
factory FCMFunctions() {
|
|
|
|
|
return _singleton;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
late FirebaseMessaging messaging;
|
|
|
|
|
|
|
|
|
|
late FlutterLocalNotificationsPlugin flip;
|
|
|
|
|
|
|
|
|
|
late InitializationSettings initSettings;
|
|
|
|
|
//************************************************************************************************************ */
|
|
|
|
|
/// Create a [AndroidNotificationChannel] for heads up notifications
|
|
|
|
|
late AndroidNotificationChannel channel;
|
|
|
|
|
|
|
|
|
|
/// Initialize the [FlutterLocalNotificationsPlugin] package.
|
|
|
|
|
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
|
|
|
|
|
|
|
|
|
|
//************************************************************************************************************ */
|
|
|
|
|
|
|
|
|
|
Future initApp() async {
|
|
|
|
|
debugPrint('init firebase');
|
|
|
|
|
await Firebase.initializeApp(
|
|
|
|
|
options: DefaultFirebaseOptions.currentPlatform,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
messaging = FirebaseMessaging.instance;
|
|
|
|
|
|
|
|
|
|
if (!kIsWeb) {
|
|
|
|
|
channel = const AndroidNotificationChannel(
|
|
|
|
|
'high_importance_channel', // id
|
|
|
|
|
'High Importance Notifications', // title
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
//for IOS Foreground Notification
|
|
|
|
|
await messaging.setForegroundNotificationPresentationOptions(
|
|
|
|
|
alert: true,
|
|
|
|
|
badge: true,
|
|
|
|
|
sound: true,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
flip = FlutterLocalNotificationsPlugin();
|
|
|
|
|
var initializationSettingsAndroid = const AndroidInitializationSettings('@drawable/ic_launcher');
|
|
|
|
|
var initializationSettingsIOs = const DarwinInitializationSettings();
|
|
|
|
|
initSettings = InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsIOs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future subscribeToTopics(String topic) async {
|
|
|
|
|
await messaging.subscribeToTopic(topic);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///Expire : https://firebase.google.com/docs/cloud-messaging/manage-tokens
|
|
|
|
|
Future<String?> getFCMToken() async {
|
|
|
|
|
final fcmToken = await messaging.getToken();
|
|
|
|
|
debugPrint('Get FCM Token ------->: $fcmToken');
|
|
|
|
|
return fcmToken;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void tokenListener() {
|
|
|
|
|
debugPrint('tokenListener');
|
|
|
|
|
messaging.onTokenRefresh.listen((fcmToken) {
|
|
|
|
|
debugPrint('Listen FCM Token ------->: $fcmToken');
|
|
|
|
|
// If necessary send token to application server.
|
|
|
|
|
}).onError((err) {
|
|
|
|
|
debugPrint('tokenListener err $err');
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// IOS
|
|
|
|
|
Future iosWebPermission() async {
|
|
|
|
|
if (Platform.isIOS || kIsWeb) {
|
|
|
|
|
/* NotificationSettings settings = */ await messaging.requestPermission();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///Foreground messages
|
|
|
|
|
///
|
|
|
|
|
///To handle messages while your application is in the foreground, listen to the onMessage stream.
|
|
|
|
|
void foreGroundMessageListener() {
|
|
|
|
|
FirebaseMessaging.onMessage.listen(_onMessageHandler);
|
|
|
|
|
FirebaseMessaging.onMessageOpenedApp.listen(_onMessageOpenedApp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// foreground
|
|
|
|
|
Future<void> _onMessageHandler(RemoteMessage message) async {
|
|
|
|
|
debugPrint('onMessageHandler');
|
|
|
|
|
_showNotificationViaFBConsole(message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// FLUTTER_NOTIFICATION_CLICK
|
|
|
|
|
|
|
|
|
|
// background (app minimized)
|
|
|
|
|
Future<void> _onMessageOpenedApp(RemoteMessage message) async => _performClickAction(message);
|
|
|
|
|
|
|
|
|
|
Future<void> _showNotification(RemoteMessage message) async {
|
|
|
|
|
final String imgUrl = message.data['imageUrl'] ?? '';
|
|
|
|
|
debugPrint('imgUrl $imgUrl');
|
|
|
|
|
final RemoteNotification? notification = message.notification;
|
|
|
|
|
|
|
|
|
|
final largeIconPath = await downloadFile(imgUrl, 'largeIcon');
|
|
|
|
|
final bigPicturePath = await downloadFile(imgUrl, 'bigPicture');
|
|
|
|
|
|
|
|
|
|
final BigPictureStyleInformation styleInformation = new BigPictureStyleInformation(
|
|
|
|
|
FilePathAndroidBitmap(bigPicturePath),
|
|
|
|
|
largeIcon: FilePathAndroidBitmap(largeIconPath),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
|
|
|
|
|
channel.id,
|
|
|
|
|
channel.name,
|
2023-10-26 05:54:22 +00:00
|
|
|
// icon: '@drawable/ic_launcher',
|
|
|
|
|
// channelDescription: channel.description,
|
2023-03-28 06:36:10 +00:00
|
|
|
// importance: Importance.max,
|
|
|
|
|
// priority: Priority.high,
|
2023-10-26 05:54:22 +00:00
|
|
|
// color: ThemeColor.mainColor,
|
2023-03-28 06:36:10 +00:00
|
|
|
styleInformation: styleInformation,
|
|
|
|
|
);
|
|
|
|
|
var iOSPlatformChannelSpecifics = DarwinNotificationDetails();
|
|
|
|
|
|
|
|
|
|
var platformChannelSpecifics = NotificationDetails(
|
|
|
|
|
android: androidPlatformChannelSpecifics,
|
|
|
|
|
iOS: iOSPlatformChannelSpecifics,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
FlutterLocalNotificationsPlugin flip = FlutterLocalNotificationsPlugin();
|
|
|
|
|
await flip.show(0, notification?.title, notification?.body, platformChannelSpecifics, payload: 'Default_Sound');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> _showNotificationViaFBConsole(RemoteMessage message) async {
|
|
|
|
|
final RemoteNotification? notification = message.notification;
|
|
|
|
|
if (notification == null) return;
|
|
|
|
|
|
|
|
|
|
final String? imgUrl = _getImageUrl(notification);
|
|
|
|
|
|
|
|
|
|
debugPrint('==> imgUrl: $imgUrl ');
|
|
|
|
|
|
|
|
|
|
BigPictureStyleInformation? styleInformation;
|
|
|
|
|
if (imgUrl != null) {
|
|
|
|
|
final largeIconPath = await downloadFile(imgUrl, 'largeIcon');
|
|
|
|
|
final bigPicturePath = await downloadFile(imgUrl, 'bigPicture');
|
|
|
|
|
|
|
|
|
|
styleInformation = new BigPictureStyleInformation(
|
|
|
|
|
FilePathAndroidBitmap(bigPicturePath),
|
|
|
|
|
largeIcon: FilePathAndroidBitmap(largeIconPath),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
|
|
|
|
|
channel.id,
|
|
|
|
|
channel.name,
|
|
|
|
|
icon: '@drawable/ic_launcher',
|
|
|
|
|
channelDescription: channel.description,
|
2023-10-26 05:54:22 +00:00
|
|
|
importance: Importance.max,
|
2023-03-28 06:36:10 +00:00
|
|
|
priority: Priority.high,
|
|
|
|
|
color: ThemeColor.mainColor,
|
|
|
|
|
styleInformation: styleInformation,
|
|
|
|
|
);
|
|
|
|
|
var iOSPlatformChannelSpecifics = DarwinNotificationDetails();
|
|
|
|
|
|
|
|
|
|
var platformChannelSpecifics = NotificationDetails(
|
|
|
|
|
android: androidPlatformChannelSpecifics,
|
|
|
|
|
iOS: iOSPlatformChannelSpecifics,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
flip.initialize(
|
|
|
|
|
initSettings,
|
|
|
|
|
// onDidReceiveBackgroundNotificationResponse: (details) {
|
|
|
|
|
// debugPrint('==> ${details.payload}');
|
|
|
|
|
// },
|
|
|
|
|
onDidReceiveNotificationResponse: (details) {
|
|
|
|
|
debugPrint('onDidReceiveNotificationResponse');
|
|
|
|
|
_performClickAction(message);
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
await flip.show(0, notification.title, notification.body, platformChannelSpecifics, payload: 'Default_Sound');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> _performClickAction(RemoteMessage message) async {
|
2023-10-25 10:19:17 +00:00
|
|
|
if (message.data['type'] == 'product') {
|
|
|
|
|
final int productId = int.parse(message.data['id']);
|
|
|
|
|
final ProductModel? model = await ProductApi.getProductById(productId);
|
|
|
|
|
if (model != null) Get.to(() => ProductDetailsPage(model: model));
|
|
|
|
|
} else if (message.data['type'] == 'category_id') {
|
|
|
|
|
final args = {
|
|
|
|
|
'type': 'category_id',
|
|
|
|
|
'id': message.data['id'],
|
|
|
|
|
'name':message.data['name']
|
|
|
|
|
};
|
|
|
|
|
navigateToProductListScreen(args);
|
|
|
|
|
} else {
|
|
|
|
|
// open dialog
|
|
|
|
|
// if (message.notification == null) return;
|
|
|
|
|
// Get.to(
|
|
|
|
|
// () => NotificationPage(title: message.notification!.title ?? '', data: message.notification!.body ?? ''),
|
|
|
|
|
// );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @params send via firebase
|
|
|
|
|
*
|
|
|
|
|
* @params for product
|
|
|
|
|
* {
|
|
|
|
|
* "type": "product",
|
|
|
|
|
* "id":1922
|
|
|
|
|
* }
|
|
|
|
|
* @params for category
|
|
|
|
|
* {
|
|
|
|
|
* "type": "category_id",
|
|
|
|
|
* "id":2
|
|
|
|
|
* "name": "Category Name",
|
|
|
|
|
* }
|
|
|
|
|
**/
|
2023-03-28 06:36:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String? _getImageUrl(RemoteNotification notification) {
|
|
|
|
|
if (Platform.isIOS && notification.apple != null) return notification.apple?.imageUrl;
|
|
|
|
|
if (Platform.isAndroid && notification.android != null) return notification.android?.imageUrl;
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final fcmFunctions = FCMFunctions();
|
|
|
|
|
|
|
|
|
|
// backgroundHandler must be on top and separated
|
|
|
|
|
Future<void> onBackgroundHandler(RemoteMessage message) async {
|
|
|
|
|
// fcmFunctions._showNotification(message);
|
|
|
|
|
fcmFunctions._showNotificationViaFBConsole(message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Future<void> initFCMFunctions() async {
|
|
|
|
|
await fcmFunctions.initApp();
|
|
|
|
|
await fcmFunctions.iosWebPermission();
|
|
|
|
|
|
|
|
|
|
FirebaseMessaging.onBackgroundMessage(onBackgroundHandler);
|
|
|
|
|
|
|
|
|
|
await fcmFunctions.getFCMToken();
|
|
|
|
|
fcmFunctions.tokenListener();
|
|
|
|
|
fcmFunctions.foreGroundMessageListener();
|
|
|
|
|
await fcmFunctions.subscribeToTopics('notifications');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* final http.Response response = await http.get(Uri.parse(URL));
|
|
|
|
|
BigPictureStyleInformation bigPictureStyleInformation =
|
|
|
|
|
BigPictureStyleInformation(
|
|
|
|
|
ByteArrayAndroidBitmap.fromBase64String(base64Encode(image)),
|
|
|
|
|
largeIcon: ByteArrayAndroidBitmap.fromBase64String(base64Encode(image)),
|
|
|
|
|
);
|
|
|
|
|
flutterLocalNotificationsPlugin.show(
|
|
|
|
|
Random().nextInt(1000),
|
|
|
|
|
title,
|
|
|
|
|
description,
|
|
|
|
|
NotificationDetails(
|
|
|
|
|
android: AndroidNotificationDetails(channel.id, channel.name,
|
|
|
|
|
channelDescription: channel.description,
|
|
|
|
|
importance: Importance.high,
|
|
|
|
|
styleInformation: bigPictureStyleInformation),
|
|
|
|
|
),
|
|
|
|
|
); */
|