Flutter Firebase background push in terminated state has not been handled.
My env and deps :
Android 11, Nokia G21
environment:
sdk: ">=2.14.0 <3.0.0"
flutter: "^3.3.6"
firebase_messaging: ^14.0.3
firebase_core: ^2.1.1
firebase_crashlytics: ^3.0.3
main.dart:
late AndroidNotificationChannel channel;
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
bool isFlutterLocalNotificationsInitialized = false;
#pragma('vm:entry-point')
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
await setupFlutterNotifications();
showFlutterNotification(message);
Logger().i("Handling a background message: ${message.messageId}");
}
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await SharedPreferences.getInstance();
await FlutterConfig.loadEnvVariables();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
await setupFlutterNotifications();
FirebaseMessaging.onMessage.listen((event) {
Logger().e('$CLASS_TAG onMessage ${event.data.toString()}');
showFlutterNotification(event);
});
runZonedGuarded(
() => runApp(const ErkcRequestApp()),
(Object object, StackTrace stackTrace) => dev.log(
object.toString(),
error: object,
stackTrace: stackTrace,
),
);
}
Used this example, also tried this, but still get error.
Error from Logcat (app in terminated state):
Related
i listen to the notification as below
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await FirebaseMessaging.instance.getToken();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(MyProject(
appRouter: AppRouting(),
));
}
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();
NotificationServices ntService = NotificationServices();
print("Handling a background message: ${message.data['room']}");
ntService.showNotification(message);
}
void showNotification(RemoteMessage message) {
flutterLocalNotificationsPlugin.show(
message.data.hashCode,
message.data['title'],
message.data['body'],
NotificationDetails(
android: AndroidNotificationDetails(
NotificationServices.channel.id,
NotificationServices.channel.name,
channelDescription: NotificationServices.channel.description,
//channel.description,
icon: 'launch_background',
playSound: true,
// other properties...
),
),
payload: message.data['room']);
}
}
await flutterLocalNotificationsPlugin.initialize(
initialzationSettings,
onDidReceiveNotificationResponse: onSelectNotification,
onDidReceiveBackgroundNotificationResponse: onSelectNotification,
);
in the onSelectNotification
i get the roomID and then navigate to it but to do so i had to but it in the homepage screen in order to set the user and room data so i get an error i should use in the top level function in the main.dart and it is working fine with the foreground notification but for the background it just open the app so any ideas of how should i do it
I assumed I followed all the steps to handling background notifications from firebase in flutter. I have created a top-level function that I am expecting to be triggered whenever a notification comes in. However, the function is never triggered.
Here's the top-level background handler function that exists in my home page widget but outside the class:
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// ignore: avoid_print
print('A background message just showed up : ${message.messageId}');
// update SQLite
var result = await PageService.instance
.add(PageService.instance.convertToPage(message.data));
print('added to db: ${result}');
}
Here is my home page init state that calls a function to initialize firebase messgaging:
#override
void initState() {
super.initState();
_initializeFirebaseMessaging();
}
And then here is the _initializeFirebaseMessaging function that is defined in the home page class as well:
void _initializeFirebaseMessaging() {
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
FirebaseMessaging.onMessage.listen((RemoteMessage message) async {
print('new notification arrived');
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
// update SQLite
var result = await PageService.instance
.add(PageService.instance.convertToPage(message.data));
print('added to db: ${result}');
if (notification != null && android != null) {
// show notification
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
color: Colors.blue,
playSound: true,
icon: '#mipmap/ic_launcher',
),
));
}
});
}
The onmessage.listen works fine as I get notificationd and handle them while I'm in the app, but the background handler is not triggered at all.
I would appreciate any help!
You have to call FirebaseMessaging.onBackgroundMessage inside your main() not in initState()
try: after main func
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
...
}
and remove WidgetsFlutterBinding.ensureInitialized(); in firebaseMessagingBackgroundHandler
onMessage handles foreground notification
onMessageOpenedApp handles background notification
Instead of using onMessage for handling Background notifications, add another function block of FirebaseMessaging with onMessageOpenedApp, if you want notification while the app is in background, like this:
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message){...})
onMessage only works when the app is in foreground.
If you want notification while the app is in the terminated state you can use:
FirebaseMessaging.instance.getInitialMessage().then((message){...})
Update your firebaseMessagingBackgroundHandler to this:
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
// ignore: avoid_print
print('A background message just showed up : ${message.messageId}');
// update SQLite
var result = await PageService.instance
.add(PageService.instance.convertToPage(message.data));
print('added to db: ${result}');
}
And finally, the main() should look like this:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
// Add Firebase Initialization:
await Firebase.initializeApp();
// This will initialize a new Firebase instance.
// Background message handler
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
runApp(const App());
}
You should call FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler); from within main(), not from Homepage initState(){}.
I divide the hms and gms services in my project, and I also created a local packages that is a collection of my own helper classes for push notification service
The dependencies of local package for gms devices include firebase_core and firebase_messaging. Dart analytics doesn't shows the problem "Undefinded" which appear when dependencies are not loaded by pub get or doesn`t exist in pubspec.yaml. But when i started debug build, it have exceptions
pubspec.yaml:
name: push_service
description: A new Flutter package project.
version: 0.0.1
homepage:
publish_to: none
environment:
sdk: ">=2.17.1 <3.0.0"
flutter: ">=1.17.0"
dependencies:
flutter:
sdk: flutter
push_service_interface:
path: ../../interface/push_service_interface
firebase_analytics: ^9.1.4
firebase_core: ^1.12.0
firebase_messaging: ^11.2.6
flutter_local_notifications: ^9.2.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
flutter:
The part of my code:
class GmsService implements IService {
#override
Future<void> init() async {
await Firebase.initializeApp();
if (Platform.isIOS) {
await Firebase.initializeApp(options: _firebaseOptions);
} else {
await Firebase.initializeApp();
}
FirebaseMessaging fcm = FirebaseMessaging.instance;
///Request permissions for Ios
await fcm.requestPermission(
alert: true,
announcement: false,
badge: true,
carPlay: false,
criticalAlert: false,
provisional: false,
sound: true,
);
}
#override
Future<String?> getToken() async {
return await FirebaseMessaging.instance.getToken();
}
#override
Future<void> backgroundHandler() async {
FirebaseMessaging.onBackgroundMessage((message) async {
if (Platform.isIOS) {
await Firebase.initializeApp(options: _firebaseOptions);
} else {
await Firebase.initializeApp();
}
log("[Firebase] Handling a background message: ${message.messageId}");
});
}
#override
Future<void> onTapWhenAppClosed({required Function() onTap}) async {
FirebaseMessaging.instance.getInitialMessage().then((message) {
if (message != null) {
onTap;
}
});
}
#override
Future<void> onTapWhenAppFon({required Function() onTap}) async {
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
onTap;
});
}
#override
Future<void> listener<T>({T? plugin}) async {
plugin as FlutterLocalNotificationsPlugin;
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
// AndroidNotification? android = message.notification?.android;
if (notification != null) {
plugin.show(
notification.hashCode,
notification.title,
notification.body,
const NotificationDetails(
iOS: IOSNotificationDetails(),
android: AndroidNotificationDetails(
'default_notification_channel',
'Notifications',
channelDescription: 'This channel is used for notifications.',
icon: '#drawable/res_notification_logo',
color: Colors.orange,
),
),
);
}
});
}
}
const FirebaseOptions _firebaseOptions = FirebaseOptions(
apiKey: "AIzaSyDlDrc6NbcGVR4rr8DTfV82dAk_vD3Jpi0",
appId: "1:150088765423:ios:23edb87f9ecb47a756301a",
messagingSenderId: "150088765423",
projectId: "android-foxfit-push",
);
And the build output:
I`m really tired to find the solution of this problem, anybody help me pls
I am coming from an old Firebase_messaging plugin 6 + to the newer Firebase_messenger plugin 10 +, I am able to do most of the thing but can't get the message data, I want to convert this code from the older plugin to a newer one and use methods like configure launch and onResume.I can receive the push notifications, foreground and background information about the message but can't read it.
class _ChatScreenState extends State<ChatScreen> {
#override
void initState() {
super.initState();
final fbm = FirebaseMessaging();
fbm.requestNotificationPermissions();
fbm.configure(onMessage: (msg) {
print(msg);
return;
}, onLaunch: (msg) {
print(msg);
return;
}, onResume: (msg) {
print(msg);
return;
});
}
What I have done so far
Under AndroidManifest.xml added
<meta-data android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="high_importance_channel" />
On main.dart
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
print('Handling a background message ${message.messageId}');
}
Future <void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
runApp(MyApp());
}
Here is where I want to get the data from the server
class _ChatScreenState extends State<ChatScreen> {
#override
void initState() {
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage message) {
if (message != null) {
print(message);
}
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
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}');
}
});
});
super.initState();
}
On Debug while the App is in the foreground
D/FLTFireMsgReceiver(15437): broadcast received for message
I/flutter (15437): Got a message whilst in the foreground!
I/flutter (15437): Message data: {}
I/flutter (15437): Message also contained a notification: Instance of 'RemoteNotification'
On Background
D/FLTFireMsgReceiver(15437): broadcast received for message
W/FirebaseMessaging(15437): Missing Default Notification Channel metadata in AndroidManifest. Default value will be used.
I/flutter (15437): Handling a background message 0:1624718321445677%ba7e1d8bba7e1d8b
Although the Notification Text and body is fine in the notification window but can't get the same info in the debug screen, it returns empty. Also is my implementation correct?
With a little bit of searching I believe the missing piece was flutter_local_notifications: ^5.0.0+4 The changes I have made in
main.dart
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();
print('Handling a background message ${message.messageId}');
}
const AndroidNotificationChannel channel = const AndroidNotificationChannel(
//for notificaiton initialization
'high_importance_channel', // id
'High Importance Notifications', // title
'This channel is used for important notifications.', // description
importance: Importance.high,
playSound: true,
);
//initialize plugin
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
FlutterLocalNotificationsPlugin();
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
//for background messaging
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
//Local Notification implementation
await flutterLocalNotificationsPlugin
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(channel);
//for firebase plugin and messaging required
await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(
alert: true, badge: true, sound: true);
runApp(MyApp());
}
In the class where I want the notification
class _ChatScreenState extends State<ChatScreen> {
#override
void initState() {
//foreground messaging
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification notification = message
.notification; //assign two variables for remotenotification and android notification
AndroidNotification android = message.notification?.android;
if (notification != null && android != null) {
print(message);
flutterLocalNotificationsPlugin.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
channel.id, channel.name, channel.description,
color: Colors.blue,
playSound: true,
icon: '#mipmap/ic_launcher'),
),
);
print(notification.title);
print(notification.body);
}
});
//Do when the user taps the notification
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
//same as above
});
super.initState();
}
Would be nice if some one update this process for IOS as I don't have a developer Id to test it.
I tried the following code. It's giving 'MissingPluginException' is not a subtype of type 'String'
Below is the code I used (pasted only notification part here). No issue in flutter doctor also.
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
class _Home extends State<HomePage> with TickerProviderStateMixin {
static FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = new FlutterLocalNotificationsPlugin();
#override
void initState() {
super.initState();
firebaseCloudMessaging_Listeners();
}
void firebaseCloudMessaging_Listeners() {
var android = new AndroidInitializationSettings('mipmap/ic_launcher',);
var ios = new IOSInitializationSettings();
var platform = new InitializationSettings(android, ios);
flutterLocalNotificationsPlugin.initialize(platform,onSelectNotification: onSelectNotification);
if (Platform.isIOS) iOS_Permission();
_firebaseMessaging.getToken().then((token){
//FCM=token;
}).catchError((onError){
print("blb07 "+onError.toString());
});
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print('blb07 on message $message');
handleNotification(message['data']['message']);
},
onResume: (Map<String, dynamic> message) async {
print('blb07 on resume $message');
handleNotification(message['data']['message']);
},
onLaunch: (Map<String, dynamic> message) async {
print('blb07 on launch $message');
handleNotification(message['data']['message']);
},
);
}
void iOS_Permission() {
_firebaseMessaging.requestNotificationPermissions(
IosNotificationSettings(sound: true, badge: true, alert: true)
);
_firebaseMessaging.onIosSettingsRegistered
.listen((IosNotificationSettings settings)
{
print("Settings registered: $settings");
});
}
Future onSelectNotification(String payload) async {
await Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new DisplayNotifications()),
);
}
void handleNotification(String message) async{
var androidPlatformChannelSpecifics = new AndroidNotificationDetails(
'default1', 'Sureworks ', 'Sureworks app notifications',
importance: Importance.Max, priority: Priority.High);
var iOSPlatformChannelSpecifics = new IOSNotificationDetails();
var platformChannelSpecifics = new NotificationDetails(
androidPlatformChannelSpecifics, iOSPlatformChannelSpecifics);
print("blb07 start");
try{
await flutterLocalNotificationsPlugin.show(0, 'Sureworks', message, platformChannelSpecifics,payload: 'item')
.then((onValue){
print("blb07 finished");
}).catchError((onError)=>print("blb07 "+onError));
print("blb07 hello end line");
}catch(e){
print("blb07 error "+e.toString());
}
}
}
my pubspec.yaml dependencies
dev_dependencies:
flutter_test:
sdk: flutter
http: ^0.11.3+16
shared_preferences: ^0.4.2
firebase_messaging: ^4.0.0+1
firebase_core: ^0.2.5
flutter_launcher_icons: ^0.7.0
paging: ^0.1.0
flutter_local_notifications: ^0.6.1
What could be the problem? messages passing to the handleNotification funtion are string format only. No problem in Receiving notification data from server.
Did you run pod install ?
If not its likely that there is something missing on the native side.
Simply open up a terminal and navigate to your flutter project root.
Then cd into the iOS folder and run pod install.
This should fix your error.
I found the solution. Migrated my Android to AndroidX. Now it's working fine. Spent more than 4 hours on it.
Migrate to AndroidX and "Invalidate caches and restart" did the trick.