I am building a Flutter app with Firebase Messaging. I am using AwesomeNotifications plugin to display the notifications.
My notifications contain the notification property, because sending data only message does not trigger the iOS if the device is rebooted.
The issue with the notification property is that it triggers flutter SDK and auto display the default notification alone with the custom notification I configured with AwesomeNotifications .
Below is my JSON code.
"message": {
"notification": {
"title": senderName,
"body": "Image Sent"
},
"token": recieverFcm,
"data": {
"name": senderName,
"body": "Image Sent",
"chatRoomId": chatRoomId,
"sender_profile_pic": senderProfilePic,
"senderUid": senderUid,
"data_type": messageType,
"image_link": message,
"click_action": "OPEN_CHAT_ROOM"
},
"android": {
"priority": "high"
},
"apns": {
"payload": {
"aps": {
"category": "OPEN_CHAT_ROOM",
"sound": "enable",
"content-available": 1,
}
}
}
}
main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
NotificationController _notificationController = NotificationController();
//Initialize firebase
await Firebase.initializeApp();
await _notificationController.startNotificationService();
//Listen for the Token change
FirebaseMessaging.instance.onTokenRefresh.listen((String token) {
print("New token: $token");
});
//Apply MultiProvider
runApp(MultiProvider(
providers: [
//provider lists
],
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
NotificationController _notificationController = NotificationController();
_notificationController.startAwesomeNotificationlistener();
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
textTheme: GoogleFonts.poppinsTextTheme(),
primaryColor: primaryColor,
backgroundColor: Colors.white,
scaffoldBackgroundColor: Colors.white,
accentColor: darkColor,
appBarTheme: AppBarTheme(
backgroundColor: Colors.white,
elevation: 0,
iconTheme: IconThemeData(color: Colors.black),
titleTextStyle: GoogleFonts.poppins(
fontSize: 16, color: darkColor, fontWeight: FontWeight.w500)),
textSelectionTheme: TextSelectionThemeData(cursorColor: darkColor),
outlinedButtonTheme: OutlinedButtonThemeData(style: outlineButtonStyle),
elevatedButtonTheme:
ElevatedButtonThemeData(style: elevatedButtonStyle),
),
routes: {
//Routes go here
},
home: LoadingScreen3(),
);
}
}
notification_controller.dart
class NotificationController {
///Start notification service
Future<void> startNotificationService() async {
NotificationService _notificationService = NotificationService();
await _notificationService.initializFirebaseeNotifications();
}
///Display a new notification in foreground
Future<void> displayNotification({
required String groupKey,
required String channelKey,
required String title,
required String body,
required String summary,
required NotificationLayout layout,
required bool displayOnBackground,
required bool displayOnForeground,
required String messageType,
String? clickAction,
String? chatRoomId,
String? chatMessageFrom,
}) async {
NotificationService _notificationService = NotificationService();
await _notificationService.createAwesomeNotification(
groupKey: groupKey,
channelKey: channelKey,
title: title,
body: body,
summary: summary,
layout: layout,
displayOnBackground: displayOnBackground,
displayOnForeground: displayOnForeground,
messageType: messageType,
clickAction: clickAction,
chatRoomId: chatRoomId,
chatMessageFrom: chatMessageFrom);
}
//Start awesome notification listener
void startAwesomeNotificationlistener() {
NotificationService _notificationService = NotificationService();
_notificationService.startAwesomeNotificationListener();
}
}
notification_service.dart
class NotificationService with ChangeNotifier {
FirebaseMessaging _messaging = FirebaseMessaging.instance;
///Start initializing the notification service
Future<void> initializFirebaseeNotifications() async {
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
//Request permission for firebase messaging
NotificationSettings settings = await _messaging.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
if (settings.authorizationStatus == AuthorizationStatus.authorized) {
print('User granted permission');
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
developer.log("REMOTE MESSAGE LISTENER");
print("REMOTE MESSAGE LISTENER");
if (message.data["data_type"] == "TEXT") {
await createAwesomeNotification(
groupKey: message.data["senderUid"],
channelKey: 'basic_channel',
title: message.data["name"],
body: message.data["body"],
summary: message.data["body"],
layout: NotificationLayout.Messaging,
displayOnBackground: true,
displayOnForeground: true,
messageType: message.data["data_type"],
clickAction: message.data["click_action"],
chatRoomId: message.data["chatRoomId"],
chatMessageFrom: message.data["senderUid"]);
} else if (message.data["data_type"] == "IMAGE") {
await createAwesomeNotification(
groupKey: message.data["senderUid"],
channelKey: 'basic_channel',
title: message.data["name"],
body: Emojis.art_framed_picture + " " + message.data["body"],
summary: message.data["body"],
layout: NotificationLayout.Messaging,
displayOnBackground: true,
displayOnForeground: true,
messageType: message.data["data_type"],
clickAction: message.data["click_action"],
chatRoomId: message.data["chatRoomId"],
chatMessageFrom: message.data["senderUid"],
);
}
});
} else {
print('User declined or has not accepted permission');
}
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage? message) {
developer.log("REMOTE MESSAGE");
if (message != null) {
developer.log(message.data.toString());
}
});
// For handling notification when the app is in background
// but not terminated
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print("onMessageOpenedApp executed");
});
await initializeAwesomeNotifications();
}
//Initialize the notification display plugin
Future<void> initializeAwesomeNotifications() async {
AwesomeNotifications().initialize('resource://drawable/logo', [
NotificationChannel(
channelGroupKey: 'basic_tests',
channelKey: 'basic_channel',
channelName: 'Basic notifications',
channelDescription: 'Notification channel for basic tests',
defaultColor: Color(0xFF9D50DD),
ledColor: Colors.white,
importance: NotificationImportance.High),
]);
}
//Create and display notification
Future createAwesomeNotification({
required String groupKey,
required String channelKey,
required String title,
required String body,
required String summary,
required NotificationLayout layout,
required bool displayOnBackground,
required bool displayOnForeground,
required String messageType,
String? clickAction,
String? chatRoomId,
String? chatMessageFrom,
}) async {
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: UniqueKey().hashCode,
groupKey: groupKey,
channelKey: channelKey,
title: title,
body: body,
summary: summary,
notificationLayout: layout,
displayOnBackground: displayOnBackground,
displayOnForeground: displayOnForeground,
payload: {
"messageType": messageType,
"clickAction": clickAction ?? "",
"chatRoomId": chatRoomId ?? "",
"chatMessageFrom": chatMessageFrom ?? ""
}),
);
}
//Start Awesome notification listener
void startAwesomeNotificationListener() {
AwesomeNotifications()
.actionStream
.listen((ReceivedNotification receivedNotification) {
developer.log("Notification clicked");
developer.log(receivedNotification.body ?? "no data");
});
}
}
// Declared as global, outside of any class
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp();
NotificationController _notificationController = NotificationController();
developer.log("background listener called");
print("Handling a background message: ${message.data}");
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
// Use this method to automatically convert the push data, in case you gonna use our data standard
//AwesomeNotifications().createNotificationFromJsonData(message.data);
if (message.data['data_type'].toString().toUpperCase() == "TEXT") {
print("Handling a background message: ${message.data['data_type']}");
await _notificationController.displayNotification(
groupKey: message.data["senderUid"],
channelKey: 'basic_channel',
title: message.data["name"],
body: message.data["body"],
summary: message.data["body"], // Anything you want here
layout: NotificationLayout.Messaging,
displayOnForeground: true,
displayOnBackground: true,
messageType: message.data["data_type"],
clickAction: message.data["click_action"],
chatRoomId: message.data["chatRoomId"],
chatMessageFrom: message.data["senderUid"]);
} else if (message.data['data_type'].toString().toUpperCase() == "IMAGE") {
Future.delayed(Duration(seconds: 2));
await _notificationController.displayNotification(
groupKey: message.data["senderUid"],
channelKey: 'basic_channel',
title: message.data["name"],
body: Emojis.art_framed_picture + " " + message.data["body"],
summary: message.data["body"], // Anything you want here
layout: NotificationLayout.Messaging,
displayOnBackground: true,
displayOnForeground: true,
messageType: message.data["data_type"],
clickAction: message.data["click_action"],
chatRoomId: message.data["chatRoomId"],
chatMessageFrom: message.data["senderUid"]);
}
}
How can I fix this issue and stop showing the custom created AwesomeNotifications only?
Related
I have create a custom notification using flutter_local_notification package , when I
send notification using FCM, two notifications are visible in both foreground and background state of application. When I click on FCM generated notification its works as usual , but while clicking on custom background notification my app start but am not able to run my logics, so please help me in handling the background custom notification
On clicking background custom notification it shows below info
Attempted to start a duplicate background isolate. Returning...
class NotificationService {
static final NotificationService _notificationService =
NotificationService._private();
NotificationService._private();
factory NotificationService() => _notificationService;
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
final AndroidNotificationChannel _androidChannel =
const AndroidNotificationChannel(
'high_importance_channel', // id
'Notifications', // title
description: 'important notification channel', // description
importance: Importance.high,
playSound: true);
final AndroidInitializationSettings _initializationSettingsAndroid =
const AndroidInitializationSettings(
'app_icon',
);
///This functions initializes Flutterlocalnotificationplugin with required settings and channels
initialize() async {
AndroidFlutterLocalNotificationsPlugin? resp =
flutterLocalNotificationsPlugin.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>();
await resp!.createNotificationChannel(_androidChannel);
resp.requestPermission();
var initializationSettings =
InitializationSettings(android: _initializationSettingsAndroid);
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onDidReceiveNotificationResponse: _handleForegroundNotification,
onDidReceiveBackgroundNotificationResponse:
_handleBackgroundNotification);
}
/// This function create the custom notifcation.
/// before calling this function , firebaseLocalNotification instance should be initialized
showNotification(RemoteMessage message) {
var initializationSettings =
InitializationSettings(android: _initializationSettingsAndroid);
flutterLocalNotificationsPlugin.initialize(initializationSettings,
onDidReceiveNotificationResponse: _handleForegroundNotification,
onDidReceiveBackgroundNotificationResponse:
_handleBackgroundNotification);
flutterLocalNotificationsPlugin.show(
1123,
message.data['title'],
message.data['body'],
const NotificationDetails(
android: AndroidNotificationDetails(
'1123',
'channel.name',
channelDescription: 'channel.description',
color: Colors.blue,
playSound: true,
),
));
}
}
///This functions handle background notification press and performs given instructions
#pragma('vm:entry-point')
_handleBackgroundNotification(NotificationResponse response) async {
await Future.delayed(Duration(seconds: 3));
Fluttertoast.showToast(
msg: "backgrrrround call nice no",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
}
///This functions handel foregroud notification press and performs given instruction
_handleForegroundNotification(NotificationResponse response) async {
await Future.delayed(Duration(seconds: 3));
Fluttertoast.showToast(
msg: "Forerground call nice no",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
}
and another class for managing FCM
class FCMService {
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
String? fcmToken;
///This function initialized FCM and start stream of token,foregroundmessage,backgroundmessage
initialize() async {
fcmToken = await FirebaseMessaging.instance.getToken();
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
debugPrint(fcmToken);
_listenToTokenStream();
_listenToForegroundMessage();
}
// /Handle background but not teminated app notification press
_listenToOnMessageOpenedApp() {
//when
FirebaseMessaging.onMessageOpenedApp.listen((message) {
print("FCM>>>>>>>> backgroud");
});
}
/// Request permission for higher sdk version
_requestNotificationPermission() async {
NotificationSettings settings = await _firebaseMessaging.requestPermission(
alert: true,
sound: true,
);
debugPrint('User granted permission: ${settings.authorizationStatus}');
}
/// listen to foreground message recieved from FCM
_listenToForegroundMessage() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
NotificationService().showNotification(message);
});
}
///Listen to streamm of token when token expires helps us to updat it
_listenToTokenStream() {
FirebaseMessaging.instance.onTokenRefresh.listen((token) {
fcmToken = token;
debugPrint(fcmToken);
}).onError((e) {
debugPrint("token refresh failed");
});
}
}
///listen background message recieve from FCM , DO NOT: perform heavy task in background
///otherwise your process may get killed
Future<void> fcmBackgroundMessageHandler(RemoteMessage message) async {
await Firebase.initializeApp();
// await NotificationService().initialize();
NotificationService().showNotification(message);
}
main method :
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FCMService().initialize();
NotificationService().initialize();
FirebaseMessaging.onBackgroundMessage(fcmBackgroundMessageHandler);
runApp(const MyApp());
}
you should listen to background messages on FCM initialization But you are doing it on main. SO remove that and add the option in FCM initialization.
I have updated your code with the required updates.
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FCMService().initialize();
NotificationService().initialize();
runApp(const MyApp());
}
/// fcm background message handler
Future<void> fcmBackgroundMessageHandler(RemoteMessage message) async {
print(message.notification!.title);
// NotificationService().showNotification(message);
}
class FCMService {
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
String? fcmToken;
///This function initialized FCM and start stream of token,foregroundmessage,backgroundmessage
initialize() async {
fcmToken = await FirebaseMessaging.instance.getToken();
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
debugPrint(fcmToken);
_listenToTokenStream();
_listenToForegroundMessage();
_listenToBackgroundMessage();
}
/// handle push notification events on background
void handlePushNotificationBackgroundEvents() {
FirebaseMessaging.onBackgroundMessage(fcmBackgroundMessageHandler);
}
// /Handle background but not teminated app notification press
_listenToOnMessageOpenedApp() {
//when
FirebaseMessaging.onMessageOpenedApp.listen((message) {
print("FCM>>>>>>>> backgroud");
});
}
/// Request permission for higher sdk version
_requestNotificationPermission() async {
NotificationSettings settings = await _firebaseMessaging.requestPermission(
alert: true,
sound: true,
);
debugPrint('User granted permission: ${settings.authorizationStatus}');
}
/// listen to foreground message recieved from FCM
_listenToForegroundMessage() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
NotificationService().showNotification(message);
});
}
///Listen to streamm of token when token expires helps us to updat it
_listenToTokenStream() {
FirebaseMessaging.instance.onTokenRefresh.listen((token) {
fcmToken = token;
debugPrint(fcmToken);
}).onError((e) {
debugPrint("token refresh failed");
});
}
}
I'm stuck. My notification in the background show twice. But in the foreground only one notification. This is my code
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
// If you're going to use other Firebase services in the background, such as Firestore,
// make sure you call `initializeApp` before using other Firebase services.
await Firebase.initializeApp();
if(
!AwesomeStringUtils.isNullOrEmpty(message.notification?.title, considerWhiteSpaceAsEmpty: true) ||
!AwesomeStringUtils.isNullOrEmpty(message.notification?.body, considerWhiteSpaceAsEmpty: true)
){
// print('message also contained a notification: ${message.notification.body}');
String imageUrl;
imageUrl ??= message.notification.android?.imageUrl;
imageUrl ??= message.notification.apple?.imageUrl;
print(imageUrl);
if(imageUrl == null){
var id = Random().nextInt(2147483647);
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: id,
title: message.notification.title,
body: message.notification.body,
color: Colors.orange,
customSound: 'resource://raw/alert',
notificationLayout: NotificationLayout.BigText,
channelKey: 'basic_channel_background',
payload: {'data':message.data['payload']}
),
actionButtons: [
NotificationActionButton(
label: 'Lihat Selengkapnya',
enabled: true,
buttonType: ActionButtonType.Default,
key: 'background',
)
]
);
}else{
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: Random().nextInt(2147483647),
title: message.notification.title,
body: message.notification.body,
bigPicture: imageUrl,
color: Colors.orange,
customSound: 'resource://raw/alert',
notificationLayout: NotificationLayout.BigPicture,
channelKey: 'basic_channel_background',
payload: {'data':message.data['payload']}
),
actionButtons: [
NotificationActionButton(
label: 'Lihat Selengkapnya',
enabled: true,
buttonType: ActionButtonType.Default,
key: 'background',
)
]
);
}
}
}
// End Background Message
and this is my foreground code
// Foreground Apps
Future<void> main() async{
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
if (!kIsWeb) {
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
await AwesomeNotifications().initialize(
'resource://mipmap/launcher_icon',
[
NotificationChannel(
channelGroupKey: 'basic_tests',
channelKey: 'basic_channel',
channelName: 'My Cahaya Notification',
channelDescription: 'Notification channel for basic tests',
icon: 'resource://mipmap/launcher_icon',
importance: NotificationImportance.High,
playSound: true,
soundSource: 'resource://raw/alert'
),
NotificationChannel(
channelGroupKey: 'basic_background',
channelKey: 'basic_channel_background',
channelName: 'My Cahaya Notification Background',
channelDescription: 'Notification channel for basic tests',
icon: 'resource://mipmap/launcher_icon',
importance: NotificationImportance.High,
playSound: true,
soundSource: 'resource://raw/alert'
),
], debug: true);
AwesomeNotifications().actionStream.listen((event) async{
print('event received!');
var data = event.toMap();
if(data['buttonKeyPressed'] == "background"){
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString("Navigate", data['payload']['data']);
}else{
_navigateToItemForeground(data['payload']['data']);
}
// do something based on event...
// AwesomeNotifications().actionSink.close();
});
}
FirebaseMessaging.onMessage.listen((RemoteMessage message) async{
RemoteNotification notification = message.notification;
AndroidNotification android = message.notification?.android;
if (notification != null && android != null && !kIsWeb) {
if(!AwesomeStringUtils.isNullOrEmpty(message.notification?.title, considerWhiteSpaceAsEmpty: true) ||
!AwesomeStringUtils.isNullOrEmpty(message.notification?.body, considerWhiteSpaceAsEmpty: true)){
print("something");
String imageUrl;
imageUrl ??= notification.android?.imageUrl;
imageUrl ??= notification.apple?.imageUrl;
if(imageUrl == null){
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: Random().nextInt(2147483647),
title: notification.title,
body: notification.body,
color: Colors.orange,
customSound: 'resource://raw/alert',
notificationLayout: NotificationLayout.BigText,
channelKey: 'basic_channel',
payload: {'data':message.data['payload']}
),
actionButtons: [
NotificationActionButton(
label: 'Lihat Selengkapnya',
enabled: true,
buttonType: ActionButtonType.Default,
key: 'test',
)
]
);
}else{
await AwesomeNotifications().createNotification(
content: NotificationContent(
id: Random().nextInt(2147483647),
title: notification.title,
body: notification.body,
bigPicture: imageUrl,
color: Colors.orange,
customSound: 'resource://raw/alert',
notificationLayout: NotificationLayout.BigPicture,
channelKey: 'basic_channel',
payload: {'data':message.data['payload']}
),
actionButtons: [
NotificationActionButton(
label: 'Lihat Selengkapnya',
enabled: true,
buttonType: ActionButtonType.Default,
key: 'test',
)
]
);
}
}
}
});
runApp(MyApp());
}
// End Foreground Apps
and this is my screenshot
screenshot
I've tried changing the awesome notification but the result is the same. Could you help me to solve that? I hope you can help me. Thank you very much
FCM payload
{
"to":"_some_fcm_token_",
//remove this
"notification": {
"title": "this is title",
"body": "this is subtitle"
},
"type": "post_like",
"data": {
"model":{"id":"dsaflkdskfklgdkgjdksakdk"},
"body": "this is subtitle",
"title": "this is title",
"click_action": "FLUTTER_NOTIFICATION_CLICK"
},
"priority": "normal"
}
The first one is manually created (locally), and the other one is automatic by Firebase.
When sending a message to your device, make sure it is a notification rather than data. The documentation mentions that if you send data it will likely be ignored as a push notification. Only use it to send packets of data to the app instead.
If your Notification is sent while the App is in background, Firebase
automatically sends a Push-Notification, so you don't need to call the show Notification manually in the App.
I solved the problem like this:
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
if (message.notification != null) {
//No need for showing Notification manually.
//For BackgroundMessages: Firebase automatically sends a Notification.
//If you call the flutterLocalNotificationsPlugin.show()-Methode for
//example the Notification will be displayed twice.
}
return;
}
Solved)
**{
"to":"_some_fcm_token_",
//remove this
//"notification": {
// "title": "this is title",
// "body": "this is subtitle"
},
"type": "post_like",
"data": {
"model":{"id":"dsaflkdskfklgdkgjdksakdk"},
"body": "this is subtitle",
"title": "this is title",
"click_action": "FLUTTER_NOTIFICATION_CLICK"
},
"priority": "normal"
}**
payload: Platform.isAndroid?
json.encode(message.data):json.encode(message.notification)
set payload data like this
I'm using Firebase notifications, with flutter. I want the notification to be a heads-up notification. After much research, on Android this is possible when the app is in the background, only by using, "data" when sending the notification, not "notification". So I send it like this:
"to": "/topics/all",
"data": {
"title": "Alert",
"body": "App maintanance is underway.",
}
and it works great.
However, I am also sending messages to ios devices. Now with iOS, the "notification" field has to be in the notification, otherwise the notification will not show up.
The problem is that when I add the "notification" field to the request, on Android the notification is shown up twice. Once due to "notification", and once because I manually display the notification as I customised, to make it pop up.
So when I send the message like this:
{
"to": "/topics/all",
"data": {
"title": "Alert",
"body": "App maintanance is underway.",
}
"notification": {
"title": "Alert",
"body": "App maintanance is underway.",
}
}
It comes into android twice.
Now I could make two topics, one for Android and one for iOS, but sometimes I send messages to specific devices with token, and I don't know if its an Android device or iOS.
How can I cater for both?
Thanks
Here is my flutter code:
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Inportance Notifications', // title
'This channel is used for important notifications.', // description
playSound: true,
importance: Importance.high,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print('A message just showed up, id: ${message.messageId}');
showNotification(message); // without this it isn't heads-up when in background
}
Future<void> setUpFirebaseMessaging(BuildContext context) async {
print('2124: setUpFirebaseMessaging');
FirebaseMessaging.onBackgroundMessage(
_firebaseMessagingBackgroundHandler);
flutterLocalNotificationsPlugin.initialize;
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
// subscribe to topic on each app start-up
await FirebaseMessaging.instance.subscribeToTopic('all');
FirebaseMessaging.instance.getToken().then((value) {
String token = value;
print('2124: Firebase Token: ${token}');
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Got a message whilst in the foreground!');
// print('Message data: ${message.data}');
RemoteNotification notification = message.notification;
// AndroidNotification android = message.notification.android;
// AndroidNotification data = message.data;
// print('hashCode ${notification.hashCode}');
print('title ${message.data['title']}');
print('body ${message.data['body']}');
// if (notification != null) {
if (message.data != null) {
showNotification(message);
};
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('A new onMessageOpenedApp event was published');
RemoteNotification notification = message.notification;
AndroidNotification android = message.notification.android;
if(notification != null && android != null){
showDialog(context: context, builder: (_){
return AlertDialog(
title: Text(notification.title),
content: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(notification.body)
],
),
),
);
});
}
});
}
void showNotification(RemoteMessage message) {
flutterLocalNotificationsPlugin.show(
message.hashCode,
message.data['title'],
message.data['body'],
// message.notification.title,
// message.notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channel.description,
color: Colors.blue,
playSound: true,
importance: Importance.max,
priority: Priority.high,
icon: '#drawable/ic_stat_output_onlinepngtools',
),
));
}
You should remove the showNotification function from _firebaseMessagingBackgroundHandler as it triggers its own notification (from local_notification package) and firebase messaging package has its own notification so we have two!!
I have built my own application in flutter and I have implemented Local notifications and also FirebaseMessaging:
final FirebaseMessaging firebaseMessaging = FirebaseMessaging();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
#override
void initState() {
super.initState();
registerNotification();
configLocalNotification();
firebaseMessaging.requestNotificationPermissions();
}
void registerNotification() {
firebaseMessaging.requestNotificationPermissions();
firebaseMessaging.configure(onMessage: (Map<String, dynamic> message) {
print('onMessage: $message');
Platform.isAndroid
? showNotification(message['notification'])
: showNotification(message['aps']['alert']);
return ;
}, onResume: (Map<String, dynamic> message) {
print('onResume: $message');
return Navigator.push(
context,
MaterialPageRoute(
builder: (context) => NotificationsScreen()));
}, onLaunch: (Map<String, dynamic> message) {
print('onLaunch: $message');
return;
});
firebaseMessaging.getToken().then((token) {
print('token: $token');
FirebaseFirestore.instance
.collection('Consultant')
.doc(firebaseUser.uid)
.update({'deviceToken': token});
}).catchError((err) {
//Fluttertoast.showToast(msg: err.message.toString());
});
}
Future selectNotification(String payload) async {
if (payload != null) {
debugPrint('notification payload: $payload');
}
await Navigator.push(
context,
MaterialPageRoute<void>(builder: (context) => NotificationsScreen(payload: payload,)),
);
}
void showNotification(message) async {
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
Platform.isAndroid
? 'it.wytex.vibeland_pro_app'
: 'it.wytex.vibeland_pro_app',
'Vibeland',
'Vibeland',
playSound: true,
enableVibration: true,
importance: Importance.max,
priority: Priority.high,
ongoing: true,
);
var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
android: androidPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics);
print(message);
print(message['body'].toString());
print(json.encode(message));
await flutterLocalNotificationsPlugin.show(0, message['title'].toString(),
message['body'].toString(), platformChannelSpecifics,
payload: json.encode(message));
await flutterLocalNotificationsPlugin.show(
0, '📩 Hai ricevuto un messaggio 📩 ', 'Controlla subito le Tue notifiche 🔔🔔', platformChannelSpecifics,
payload: 'item x',
);
}
void configLocalNotification() {
var initializationSettingsAndroid =
new AndroidInitializationSettings('vibeland_pro');
var initializationSettingsIOS = new IOSInitializationSettings(
requestAlertPermission: true,
requestBadgePermission: true,
requestSoundPermission: true,
);
var initializationSettings = new InitializationSettings(
android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
flutterLocalNotificationsPlugin.initialize(initializationSettings);
}
I wrote a function into index.js to push also firestore notification when user creates order etc..
Everything works fine, I got Localnotifications when all is open and FCM notifications when app is in background, the problem is when the app sleep...
after some minutes the app goes in sleep mode and to start it again you need to restart the application which keep my user Logged:
MultiProvider(
providers: [
Provider<AuthenticationProvider>(
create: (_) => AuthenticationProvider(FirebaseAuth.instance),
),
StreamProvider(
create: (context) => context.read<AuthenticationProvider>().authState,
)
],
child: MaterialApp(
theme: ThemeData(
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.android: CupertinoPageTransitionsBuilder(
),
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
}
)
),
debugShowCheckedModeBanner: false,
title: 'Vibeland Admin Authentication',
home: Authenticate(),
),
);
}
}
class Authenticate extends StatelessWidget {
#override
Widget build(BuildContext context) {
final firebaseUser = context.watch<User>();
if (firebaseUser != null) {
return StartScreenLogged();
}
return StartScreen();
}
}
but if I dont run again the app I dont get the notification because the app sleep.
what we need to do in this case?
Im using a solution with FCM and Local notifications to receive specific push notifications on a channel. Everything works for Android.
I send my push notifications trough Postman to https://fcm.googleapis.com/fcm/send and that all works pretty well.
However when I add my iPhone, and finished all the installation steps that were needed. The only thing I receive is the print in my console on flutter with the message. I don't receive any kind of notification on the iPhone itself.
final FirebaseMessaging _fcm = FirebaseMessaging();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
var initializationSettingsAndroid;
var initializationSettingsIOS;
var initializationSettings;
void _showNotification() async {
//await _buildNotification();
}
Future<dynamic> myBackgroundMessageHandler(Map<String, dynamic> message) {
if (message.containsKey('data')) {
// Handle data message
final dynamic data = message['data'];
}
if (message.containsKey('notification')) {
// Handle notification message
final dynamic notification = message['notification'];
}
// Or do other work.
}
Future<void> _createNotificationChannel(
String id, String name, String description) async {
final flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
var androidNotificationChannel = AndroidNotificationChannel(
id,
name,
description,
importance: Importance.Max,
playSound: true,
sound: RawResourceAndroidNotificationSound('not_kiddin'),
enableVibration: true,
);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(androidNotificationChannel);
}
Future<void> _buildNotification(String title, String body) async {
var androidPlatformChannelSpecifics = AndroidNotificationDetails(
'my_channel',
'Channel Name',
'Channel Description.',
importance: Importance.Max,
priority: Priority.High,
playSound: true,
enableVibration: true,
sound: RawResourceAndroidNotificationSound('not_kiddin'),
ticker: 'noorderlicht');
var iOSChannelSpecifics = IOSNotificationDetails();
var platformChannelSpecifics = NotificationDetails(
androidPlatformChannelSpecifics, iOSChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0, title, body, platformChannelSpecifics,
payload: 'payload');
}
#override
void initState() {
super.initState();
initializationSettingsAndroid =
AndroidInitializationSettings('ic_launcher');
initializationSettingsIOS = IOSInitializationSettings(
onDidReceiveLocalNotification: onDidReceiveLocalNotification);
initializationSettings = InitializationSettings(
initializationSettingsAndroid, initializationSettingsIOS);
_fcm.requestNotificationPermissions();
_fcm.configure(
onMessage: (Map<String, dynamic> message) async {
print(message);
flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: onSelectNotification);
//_showNotification();
Map.from(message).map((key, value) {
print(key);
print(value);
print(value['title']);
_buildNotification(value['title'], value['body']);
});
},
onLaunch: (Map<String, dynamic> message) async {
print("onLaunch: $message");
},
onResume: (Map<String, dynamic> message) async {
print("onResume: $message");
},
);
}
Future onDidReceiveLocalNotification(
int id, String title, String body, String payload) async {
// display a dialog with the notification details, tap ok to go to another page
showDialog(
context: context,
builder: (BuildContext context) => CupertinoAlertDialog(
title: Text(title),
content: Text(body),
actions: [
CupertinoDialogAction(
isDefaultAction: true,
child: Text('Ok'),
onPressed: () {},
)
],
),
);
}
Future onSelectNotification(String payload) async {
if (payload != null) {
debugPrint('Notification payload: $payload');
}
}
_fcm.requestNotificationPermissions();
You need to request for permission in iOS (android dont need).
_fcm.requestNotificationPermissions(
const IosNotificationSettings(
sound: true, badge: true, alert: true, provisional: true));
FCM messages come in different structures for IOS, in your case remove the 'data' when the platform is IOS like these below.
if(Platform.isAndroid){
roomId = message['data']['chatRoomId'];
senderId = message['data']['senderId'];
}else if(Platform.isIOS){
roomId = message['chatRoomId'];
senderId = message['senderId'];
}