The context: I have a flutter app in which it is my goal to handle push notifications messages with firebase messaging to users who are subscribed to a topic. The notification is sent with data that is saved locally using SharedPreferences in the handlers. This works in 5 out of 6 scenario's.
This scenario works on Android and IOS both when:
- The app is on the foreground, the handler is called and data is stored.
- The app is on the background but not killed/terminated. The handler is called and data is stored.
- [Android only] The app is terminated from the open apps view.
The one scenario in which the onBackgroundMessage()
handler is not called (even though the push notification comes through and is displayed), is on IOS when the app is terminated. The handler does however work when you send a second push notification right after the first one, because the first one wakes up the app.
I even tried using the getInitialMessage()
to get a message after opening the app which I put in my main()
function. However that handler isn't called either. So I currently have no way of handling data in the flow which I get from firebase push notifications on IOS when the app is terminated, even though the user does receive a push notification.
What I already have done:
- Everything described here until the advanced steps (I didn't need custom image in my use case)
- I also enabled Background processing just to be sure.
- Tested using real devices, not emulators.
- Ran the app in release mode using
flutter run --release
Here is the main
and the handlers:
Future<void> firebaseMessagingForegroundHandler(
RemoteMessage message, BuildContext context) async {
// print("Handling a foreground message: ${message.notification?.title}");
var prefs = await SharedPreferences.getInstance();
var unreadMessages = prefs.getString('unreadMessages') ?? "";
var readMessages = prefs.getString('readMessages') ?? "";
int lastIndex = await getLastTabIndex();
if (lastIndex == 2) {
if (readMessages.isEmpty) {
prefs.setString('readMessages', jsonEncode([message.data]));
} else {
var listWithReadMessages = jsonDecode(readMessages);
listWithReadMessages.add(message.data);
prefs.setString('readMessages', jsonEncode(listWithReadMessages));
}
} else {
if (unreadMessages.isEmpty) {
prefs.setString('unreadMessages', jsonEncode([message.data]));
} else {
var listWithUnreadMessages = jsonDecode(unreadMessages);
listWithUnreadMessages.add(message.data);
prefs.setString('unreadMessages', jsonEncode(listWithUnreadMessages));
}
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Nieuwe melding van ${message.data['sender']}')));
}
@pragma('vm:entry-point')
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
debugPrint("Handling a background message: ${message.messageId}");
//To ensure the sharedpreferences plugin is loaded in.
DartPluginRegistrant.ensureInitialized();
var prefs = await SharedPreferences.getInstance();
prefs.reload();
var unreadMessages = prefs.getString('unreadMessages');
if (unreadMessages == null) {
prefs.setString('unreadMessages', jsonEncode([message.data]));
} else {
var listWithUnreadMessages = jsonDecode(unreadMessages);
listWithUnreadMessages.add(message.data);
prefs.setString('unreadMessages', jsonEncode(listWithUnreadMessages));
}
}
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
var messaging = FirebaseMessaging.instance;
await messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
await messaging
.getInitialMessage()
.then((message) => firebaseMessagingBackgroundHandler);
runApp(const ProviderScope(child: MyApp()));
}
I run the FirebaseMessaging.onMessage.listen((message)
from a different widget in the initState()
not in my main()
.