-
Notifications
You must be signed in to change notification settings - Fork 4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
🐛 [firebase_messaging] Silent notifications not handled on iOS #8277
Comments
@Johandrex
And see if it helps ? |
Sadly, neither
nor
works. |
@Johandrex Also, do make sure you are handling foreground notifications as mentioned in the document: https://firebase.flutter.dev/docs/messaging/notifications#foreground-notifications |
Thanks for the answer, getAPNSToken() does indeed result in a token. But this can't be sent to firebase through postman as it returns the following error The foreground notifications are handled in the same way as the link explains. Also, I just want to reiterate that the notifications does reach the phone when |
Ok, this is a new update for me based on our conversation so far :-) which has given a new angle to the issue, probably I was trying to give you solutions from a different perspective. Also, how is Android behavior when it comes to handling this behavior ? |
Sorry, might not've explained it clearly enough. The Android behavior works as expected. When receiving the silent notification on Android it's being handled by the app in both the foreground and background. But when receiving the exact same type of silent notification on iOS there's no indication of the app receiving the silent notification. See the notification service I have created down below.
|
Thanks for the update. /cc @russellwheatley |
I'm having the same issues on Upgrading my Flutter SDK didn't help either. Code: FirebaseMessaging.onMessage.listen((message) async {
Log.info(message);
Log.info(message.notification?.title);
Log.info(message.notification?.body);
Log.info(message.data);
// ...
}); It works with non-data-only notifications. But data-only never trigger the |
I had to downgrade to |
Will try this shortly, how did the notification you sent to firebase look like? Did it contain a 'data' field etc? Does the silent notification work in both the background and foreground? |
They would display if "content_available:true", this way they can be used as alternative to "notification" when they are required (eg. an encrypted payload that must be decrypted before being showed in the notification badge). We need to understand if it is an issue of firebase messaging not triggering foreground and background method or it is an issue of flutter local notification. We have no way to figure this out. |
So, if I understand you correctly, you're receiving the message in the message stream as shown in the video clip. But flutter local notification is failing to show a notification? In my instance, in the foreground, I received the message in the message stream and also had a local notification pop up as I implemented it. Of course, I had to remove the if statement here in the example. For background silent notifications, I was still able to use local flutter notifications to trigger a pop up notification. |
@russellwheatley can you paste here the main? We are not able to receive background notifications I mean a link to the file we can download on googledrive or elsewhere. |
I'm running |
@russellwheatley can you send the main somehow? |
We are using below notification body
We send notification from our server to both android and iOS users. In Let us know if the above-mentioned issue is different from current ticket, we will file a new ticket if that is the case. |
@abdulrehmank7 yes it is different. To have Silent Notifications only you should remove this. "notification": { We personally receive notification with no issue if we add "notification" in the payload, but as said, that is not a silent notification. |
@russellwheatley doesnt work. Can you please share file zipped somewhere? Thx |
So we need to send body without notification tag for |
@russellwheatley Here is our custom main everyone can paste inside firebase message example https://drive.google.com/file/d/10uHILwLnGPz2cCvuhi3uejt_jLeiO3If/view?usp=sharing Report is:
We don't think it is flutter_local_notification issue because _firebaseMessagingBackgroundHandler is never triggered. Payload is: |
Just tested again this morning. Here is // Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'message.dart';
import 'message_list.dart';
import 'permissions.dart';
import 'token_monitor.dart';
import 'firebase_options.dart';
/// Define a top-level named handler which background/terminated messages will
/// call.
///
/// To verify things are working, check out the native platform logs.
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await flutterLocalNotificationsPlugin.show(
2,
'notification.title',
message.data.toString(),
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channel.description,
// TODO add a proper drawable resource to android, for now using
// one that already exists in example app.
icon: 'launch_background',
),
),
);
// 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(options: DefaultFirebaseOptions.currentPlatform);
print('Handling a background message ${message.messageId}');
}
/// Create a [AndroidNotificationChannel] for heads up notifications
late AndroidNotificationChannel channel;
/// Initialize the [FlutterLocalNotificationsPlugin] package.
late FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
// Set the background messaging handler early on, as a named top-level function
FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
if (!kIsWeb) {
channel = const AndroidNotificationChannel(
'high_importance_channel', // id
'High Importance Notifications', // title
'This channel is used for important notifications.', // description
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);
/// Update the iOS foreground notification presentation options to allow
/// heads up notifications.
await FirebaseMessaging.instance
.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
runApp(MessagingExampleApp());
}
/// Entry point for the example application.
class MessagingExampleApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Messaging Example App',
theme: ThemeData.dark(),
routes: {
'/': (context) => Application(),
'/message': (context) => MessageView(),
},
);
}
}
// Crude counter to make messages unique
int _messageCount = 0;
/// The API endpoint here accepts a raw FCM payload for demonstration purposes.
String constructFCMPayload(String? token) {
_messageCount++;
return jsonEncode({
'token': token,
'data': {
'via': 'FlutterFire Cloud Messaging!!!',
'count': _messageCount.toString(),
},
'notification': {
'title': 'Hello FlutterFire!',
'body': 'This notification (#$_messageCount) was created via FCM!',
},
});
}
/// Renders the example application.
class Application extends StatefulWidget {
@override
State<StatefulWidget> createState() => _Application();
}
class _Application extends State<Application> {
String? _token;
@override
void initState() {
super.initState();
FirebaseMessaging.instance
.getInitialMessage()
.then((RemoteMessage? message) {
if (message != null) {
Navigator.pushNamed(
context,
'/message',
arguments: MessageArguments(message, true),
);
}
});
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
RemoteNotification? notification = message.notification;
AndroidNotification? android = message.notification?.android;
flutterLocalNotificationsPlugin.show(
1,
'notification.title',
message.data.toString(),
NotificationDetails(
android: AndroidNotificationDetails(
channel.id,
channel.name,
channel.description,
// TODO add a proper drawable resource to android, for now using
// one that already exists in example app.
icon: 'launch_background',
),
),
);
});
FirebaseMessaging.onMessageOpenedApp.listen((RemoteMessage message) {
print('A new onMessageOpenedApp event was published!');
Navigator.pushNamed(
context,
'/message',
arguments: MessageArguments(message, true),
);
});
}
Future<void> sendPushMessage() async {
if (_token == null) {
print('Unable to send FCM message, no token exists.');
return;
}
try {
await http.post(
Uri.parse('https://api.rnfirebase.io/messaging/send'),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: constructFCMPayload(_token),
);
print('FCM request for device sent!');
} catch (e) {
print(e);
}
}
Future<void> onActionSelected(String value) async {
switch (value) {
case 'subscribe':
{
print(
'FlutterFire Messaging Example: Subscribing to topic "fcm_test".',
);
await FirebaseMessaging.instance.subscribeToTopic('fcm_test');
print(
'FlutterFire Messaging Example: Subscribing to topic "fcm_test" successful.',
);
}
break;
case 'unsubscribe':
{
print(
'FlutterFire Messaging Example: Unsubscribing from topic "fcm_test".',
);
await FirebaseMessaging.instance.unsubscribeFromTopic('fcm_test');
print(
'FlutterFire Messaging Example: Unsubscribing from topic "fcm_test" successful.',
);
}
break;
case 'get_apns_token':
{
if (defaultTargetPlatform == TargetPlatform.iOS ||
defaultTargetPlatform == TargetPlatform.macOS) {
print('FlutterFire Messaging Example: Getting APNs token...');
String? token = await FirebaseMessaging.instance.getAPNSToken();
print('FlutterFire Messaging Example: Got APNs token: $token');
} else {
print(
'FlutterFire Messaging Example: Getting an APNs token is only supported on iOS and macOS platforms.',
);
}
}
break;
default:
break;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Cloud Messaging'),
actions: <Widget>[
PopupMenuButton(
onSelected: onActionSelected,
itemBuilder: (BuildContext context) {
return [
const PopupMenuItem(
value: 'subscribe',
child: Text('Subscribe to topic'),
),
const PopupMenuItem(
value: 'unsubscribe',
child: Text('Unsubscribe to topic'),
),
const PopupMenuItem(
value: 'get_apns_token',
child: Text('Get APNs token (Apple only)'),
),
];
},
),
],
),
floatingActionButton: Builder(
builder: (context) => FloatingActionButton(
onPressed: sendPushMessage,
backgroundColor: Colors.white,
child: const Icon(Icons.send),
),
),
body: SingleChildScrollView(
child: Column(
children: [
MetaCard('Permissions', Permissions()),
MetaCard(
'FCM Token',
TokenMonitor((token) {
_token = token;
return token == null
? const CircularProgressIndicator()
: Text(token, style: const TextStyle(fontSize: 12));
}),
),
MetaCard('Message Stream', MessageList()),
],
),
),
);
}
}
/// UI Widget for displaying metadata.
class MetaCard extends StatelessWidget {
final String _title;
final Widget _children;
// ignore: public_member_api_docs
MetaCard(this._title, this._children);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
margin: const EdgeInsets.only(left: 8, right: 8, top: 8),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
Container(
margin: const EdgeInsets.only(bottom: 16),
child: Text(_title, style: const TextStyle(fontSize: 18)),
),
_children,
],
),
),
),
);
}
}
|
@russellwheatley Curiosity, what happens on your device with my main? Tested your main, same result:
|
Which flutter / ios versions are you testing with? |
Flutter doctor: iOS 15.5
|
Tested on other iphone with os 15.5 and it works for me as well. IMG_7927.mov |
@russellwheatley Also, behaviour is strange. Notifications work in background only after a first one is received in foreground. That is a bug surely. |
Good news to everyone scourged by this issue. When they dont work, try this:
This fixed the issue on iphone running 15.4.1. |
@iosephmagno where is your main? And what did you guys change that it is working now and did not before? Will there be a fix of firebase_messaging itself then or was it some kind of configuration in the receiving app? Had the same issue with firebase_messaging: ^11.2.12 on iOS and did not debug further yet. |
If you have some trouble with I guess that Fixed current problem by above workaround in foreground/background in iOS 15.5, firebase_messaging 11.4.1. |
It's finally working!!! Thank you so much @russellwheatley. The reason why it didn't work before was because I was setting Working on iOS 15.5, Flutter 2, firebase_messaging 11.4.1. Here's the working data-only payload, which works on iOS both in the foreground and background if anyone want to test it with postman (POST, url: https://fcm.googleapis.com/fcm/send).
My NotificationService
|
DVR warnings have higher priority. We need the application to be "awaken" from background for sending notifications from Flutter, because we are only consuming the data from payload (and not notification). contentAvailable: true causes inactive client app on iOS to be awoken. On Android, data messages wake the app by default. priority: 'high' makes the data to be received immediately on the client app. By default, data-only payload shows with priority: 'normal' (causes some unspecified delay, battery-consumption etc). Since, notification key is now removed from the payload, it is important to set the priority to `high` explicitly. A discussion regarding this can be seen at: firebase/flutterfire#8277 (comment) https://firebase.google.com/docs/cloud-messaging/http-server-ref
Bug report
The issue is regarding silent notifications that are sent from firebase on iOS. When a silent notification is sent through firebase, the android app can handle the notification both in the foreground and background. Silent notifications can however not be handled on iOS, neither in the foreground or background, the app doesn't get any indication of the app receiving the notification.
Steps to reproduce
Steps to reproduce the behavior:
"notification": { "body": "1" }
Expected behavior
The iOS app should be able to handle silent notifications, just like the android app currently can.
Additional context
The bug occurs when using 'firebase_messaging' 11.2.10, flutter 12.2.1 on iOS 15.3.1
Flutter doctor
Run
flutter doctor
and paste the output below:Click To Expand
Flutter dependencies
Run
flutter pub deps -- --style=compact
and paste the output below:Click To Expand
The text was updated successfully, but these errors were encountered: