I am trying to send push notifications to the users of my app using FirebaseMessaging ^8.0.0-dev.14 but I am having some trouble. I am able to receive the notifications on IOS but nothing shows up on my Android emulator. I have listeners set up on init but they only see the notification on IOS devices. Has anyone had a similar issue or know how to get the notifications to show on Android? Here is my code:
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart'
as locNots;
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:url_launcher/url_launcher.dart';
import '../widgets/mentorActionsButton.dart';
import '../widgets/list_of_events.dart';
import 'userPage.dart';
import 'loginPage.dart';
class MentorMainPage extends StatefulWidget {
#override
_MentorMainPageState createState() => _MentorMainPageState();
}
class _MentorMainPageState extends State<MentorMainPage> {
#override
void initState() {
super.initState();
final fbm = FirebaseMessaging.instance;
// IOS Configurations
fbm.setForegroundNotificationPresentationOptions(
alert: true, badge: true, sound: true);
fbm.requestPermission();
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('IOS Listener');
print('Got a message whilst in the foreground!');
print('Message data: ${message.data}');
if (message.notification != null) {
print('Message also contained a notification: ${message.notification}');
}
});
//Android Configurations
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
'This channel is used for important notifications.', // description
importance: Importance.max,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
print('Android Listener');
RemoteNotification notification = message.notification;
AndroidNotification android = message.notification?.android;
print('Android Notification:');
if (notification != null && android != null) {
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id, channel.name, channel.description,
icon: android?.smallIcon,
showWhen: false,
importance: Importance.max,
priority: locNots.Priority.high),
));
}
});
}
var userLoggedIn = true;
#override
Widget build(BuildContext context) {
Code for screen view.....
}
add these before calling onMessage()
await Firebase.initializeApp(); // necessary for initializing firebase
FirebaseMessaging.instance.getInitialMessage().then((RemoteMessage message) {
print('message recived');
});
try making main function async and adding the previous lines there
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 working on a Flutter App with Firebase Messaging. The notifications work perfectly fine on iOS. On Android, they work when the app is in the foreground, but are not displayed when the app is in background or terminated. I could already rule out doze mode, as the app has been put to background just seconds before triggering the message. The logfile also says, the message is received by the devices, but somehow not displayed.
The problem also only exists when the app is installed via .apk and not when I build directly with Android Studio, so I thought maybe the fingerprinting could cause the problem. But the messages are received by the device and just not displayed -> so that's not it either, right?
I use firebase_messaging: ^12.0.0 as the plugin.
Here is the implementation of my background handler:
static Future<void> setUp() async {
await Firebase.initializeApp(
name: 'Firebase-App',
options: DefaultFirebaseOptions.currentPlatform,
);
//... iOS stuff
//Enable Foreground-Messages for Android
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description:
'This channel is used for important notifications.', // description
importance: Importance.max,
);
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
await configLocalNotification(flutterLocalNotificationsPlugin);
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
//Display Foreground-Message on Android
flutterLocalNotificationsPlugin.show(
message.hashCode,
Uri.decodeComponent(message.data['title']).replaceAll('+', ' '),
Uri.decodeComponent(message.data['message']).replaceAll('+', ' '),
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
icon: '#mipmap/ic_launcher',
importance: Importance.max,
),
),
payload: json.encode(message.data),
);
});
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true, badge: true, sound: true);
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
}
static Future<void> _firebaseMessagingBackgroundHandler(
RemoteMessage message) async {
await Firebase.initializeApp();
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
const AndroidNotificationChannel channel = AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
description:
'This channel is used for important notifications.', // description
importance: Importance.max,
);
await flutterLocalNotificationsPlugin.show(
message.hashCode,
Uri.decodeComponent(message.data['title']).replaceAll('+', ' '),
Uri.decodeComponent(message.data['message']).replaceAll('+', ' '),
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channelDescription: channel.description,
icon: '#mipmap/ic_launcher',
importance: Importance.max,
// other properties...
),
),
payload: json.encode(message.data),
);
}
static Future<void> configLocalNotification(
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin) async {
const initializationSettingsAndroid =
AndroidInitializationSettings('#mipmap/ic_launcher');
const initializationSettingsIOS = IOSInitializationSettings();
const initializationSettings = InitializationSettings(
iOS: initializationSettingsIOS, android: initializationSettingsAndroid);
//Handle on click event when App is in foreground or background
await flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: onSelectNotification);
//handle on click event when app is terminated
final NotificationAppLaunchDetails? notificationAppLaunchDetails =
await flutterLocalNotificationsPlugin.getNotificationAppLaunchDetails();
if (notificationAppLaunchDetails?.didNotificationLaunchApp ?? false) {
final String? selectedNotificationPayload =
notificationAppLaunchDetails!.payload;
debugPrint(
'notification payload on launch: $selectedNotificationPayload');
await onSelectNotification(selectedNotificationPayload);
}
}
Thanks in advance for your help, I'm really at the end of the line here!
enter image description hereI am new to Flutter and as I have added Firebase Messaging in my project for notification, it started to have 2 main call stacks. I am using Flutter sdk >=2.17.6<3.0.0, firebase_messaging: ^14.0.3, and flutter_local_notifications: ^12.0.3. Please give me some help if anyone understand the issue here.
Here is my main dart for runApp:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
//notification
await firebaseMessaging.getInitialMessage();
FirebaseMessaging.onBackgroundMessage(backgroundMessagesHandler);
//Set screen orientation to potrait
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
runApp(const MyApp());
}
And here is my backgroundMessaging function definition:
Future<void> backgroundMessagesHandler(RemoteMessage message) async {
await setupFlutterNotifications();
showFlutterNotification(message);
debugPrint(
"Background Message: ${message.notification!.title} ** ${message.notification!.body}");
}
late AndroidNotificationChannel channel;
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
final firebaseMessaging = FirebaseMessaging.instance;
bool isFlutterLocalNotificationsInitialized = false;
Future<void> setupFlutterNotifications() async {
if (isFlutterLocalNotificationsInitialized) {
return;
}
channel = const AndroidNotificationChannel(
'Demo', // id
'Demo', // title
description: 'Welcome.', // description
importance: Importance.high,
);
flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin();
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
await firebaseMessaging.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
isFlutterLocalNotificationsInitialized = true;
}
I have tried restructuring the main run app by removing async but the problem still remain
The call stack issue
I want to bring an app in the background to the foreground. This link use a package that is not working and although the author has done a tremendous job it has seen no updates for 11 months.
So I am looking for a solution to bring the app in the background to the foreground or even (re)launch the app. I have spent countless hours trying different packages and none of them work, here is the list:
import 'package:bringtoforeground/bringtoforeground.dart';
import 'package:android_intent/android_intent.dart';
import 'package:flutter_appavailability/flutter_appavailability.dart';
import 'flutterIntent.dart';
flutterIntent.dart is thanks to this repository: https://github.com/sunsetjesus/flutter_intent
import 'dart:async';
import 'package:flutter/services.dart';
class FlutterIntent {
static const MethodChannel _channel = const MethodChannel('flutter_intent');
static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
}
static Future<void> openApp(String appId, String targetActivity) async {
await _channel.invokeMapMethod('openApp', {"appId": appId,"targetActivity": targetActivity});
}
}
Not to mention the last of solution for IOS.
I am quite astonished that there are so many good packages but there seems to be no default solution to open an app (which we can do by tapping twice on the icon...). It is very simple to start another app when coding for Windows or Linux platform so I am really amazed that it requires so much effort when it comes to mobile.
Thank you very much for any help,
PS: Actually I don't even need to bring the app back to the foreground, originally I was trying to have await launch(url); on notification received, so launching chrome/firefox/safari with the url (that I get with no problem) would be good enough in my usecase.
I solved it myself thanks to flutter local notification package, example below:
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
Future _showNotification(FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin) async {
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
'your channel id', 'your channel name', 'your channel description',
importance: Importance.max, priority: Priority.high);
var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
android: androidPlatformChannelSpecifics, iOS: iOSPlatformChannelSpecifics);
await flutterLocalNotificationsPlugin.show(
0,
'New Notification',
'Flutter is awesome',
platformChannelSpecifics,
payload: 'This is notification detail Text...',
);
}
static FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
static onBackgroundMessage(SmsMessage message) async {
String encodedUrl = message.body;
debugPrint("onBackgroundMessage called $encodedUrl");
print('app available');
await _showNotification(flutterLocalNotificationsPlugin);
}
Future onSelectNotification(String payload) async {
showDialog(
context: context,
builder: (_) {
return new AlertDialog(
title: Text("Your Notification Detail"),
content: Text("Payload : $payload"),
);
},
);
}
void localNotification() {
var initializationSettingsAndroid =
new AndroidInitializationSettings('app_icon');
var initializationSettingsIOS = new IOSInitializationSettings();
var initializationSettings = new InitializationSettings(android: initializationSettingsAndroid, iOS: initializationSettingsIOS);
flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
flutterLocalNotificationsPlugin.initialize(initializationSettings,
onSelectNotification: onSelectNotification);
}
And in StatefulWidget:
#override
void initState() {
super.initState();
localNotification();
}
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'];
}