I am developing a flutter app for both Android and iOS. It has notifications, so I did implement the firebase_messaging API. I am sending notifications to certain devices by device ID and sending notifications to topics
as well.
I am testing the topics
notification sending, which is working 100% fine in Android. I followed the guide in above provided link, implemented iOS setups as well. But in iOS, when the notification is sent, it is being received by app only if it is in foreground. Which means, only via onMessage
. If the app is in background or closed, I see no notification (I am printing it in console). But when I reopen the app, the notification gets printed.
Below are my notification register code
FirebaseMessagesImpl msg = FirebaseMessagesImpl();
msg.requestPermissions();
//Get configured with firebase messaging to recieve messages
msg.getMessage().then((_) {
msg.register().then((String token) {
print(token);
//Register to the `topic` so we get messages sent to the topic
msg.topicRegister();
.........
}
FirebaseMessagesImpl
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:http/http.dart' as http;
import 'dart:convert' as convert;
class FirebaseMessagesImpl {
final FirebaseMessaging _firebaseMessaging = FirebaseMessaging();
String serverToken =
"AAAAAAA:XXXXXXXXX-YYYYYYYY-ZZZZ-BBBBBBBB";
Future<String> register() async {
String token = "";
_firebaseMessaging.getToken().then((t) {
token = t;
print("ha: " + t);
});
return token;
}
Future<void> getMessage() async {
_firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print('on message $message');
//setState(() => _message = message["notification"]["title"]);
}, onResume: (Map<String, dynamic> message) async {
print('on resume $message');
// setState(() => _message = message["notification"]["title"]);
}, onLaunch: (Map<String, dynamic> message) async {
print('on launch $message');
//setState(() => _message = message["notification"]["title"]);
});
}
void topicRegister() {
// _firebaseMessaging.subscribeToTopic("mobile_admin");
_firebaseMessaging.subscribeToTopic("puppies");
}
void requestPermissions() async
{
await _firebaseMessaging.requestNotificationPermissions(
const IosNotificationSettings(sound:true, badge:true, alert:true, provisional:false)
);
}
}
Below is my Info.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>MY APP NAME</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
Below is AppDelegate.swift
import UIKit
import Flutter
import Firebase
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure()
GeneratedPluginRegistrant.register(with: self)
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
}
As some people recommended in OTHER SO answers, I removed the following section from the AppDelegate.swift code and tried, still the same issue persists.
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
I HAVE uploaded the apple key file to Firebase project cloud messaging
section as in the guide as well.
Below is my JSon code sending notifications
{
"notification": {
"body": "body",
"title": "title"
},
"priority": "high",
"data": {
"body": "body",
"title": "title",
"click_action": "FLUTTER_NOTIFICATION_CLICK",
"id": "1",
"status": "done",
"image": "https://ibin.co/2t1lLdpfS06F.png"
},
"to": "/topics/puppies"
}
My Signin Capabilities are as follows
I am new to iOS and can't figure out whats going on. I thought just like in Android, the notification will auto appear in notification bar when the app is in background or closed.
Update
As suggestion by @nandish, I changed the AppDelegate.swift
file as below
import UIKit
import Flutter
import Firebase
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate, UNUserNotificationCenterDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure()
GeneratedPluginRegistrant.register(with: self)
UNUserNotificationCenter.current().delegate = self
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Messaging.messaging().apnsToken = deviceToken
super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)
}
// MARK: - UNUserNotificationCenterDelegate Method
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert])
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
}
}
Then I ended up with the following error
UNUserNotificationCenter' is only available in iOS 10.0 or newer
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
Update
In foreground, I am getting the following response from the app when a notification is issued. Thats also only in iPhone Simulator, not in real device.
{from: /topics/puppies, status: done, id: 1, notification: {body: body, title: title, e: 1, tag: topic_key_9204266xxxxxxx535}, title: title, image: https://ibin.co/2t1lLdpfS06F.png, collapse_key: com.aaa.xxx, body: body, click_action: FLUTTER_NOTIFICATION_CLICK}
Foreground and Notification messages Notification messages which arrive while the application is in the foreground will not display a visible notification by default, on both Android and iOS. It is, however, possible to override this behavior: On Android, you must create a "High Priority" notification channel.
Open Android Studio and create a new flutter application project with a name called 'geeksforgeeks'. Once the project is created and sync successfully, connect your Android device to Android Studio and make sure Developer options and USB debugging are On.
In the main app target, select Signing & Capabilities > All > + Capability and then search "push." Double-click on Push Notifications to enable it. Next, enable Background Modes and check Remote Notifications. Now you are ready to send notifications from the OneSignal dashboard!
i had a very similar issue when they discovered an issue in firebase_messaging 6.0.16 now its been updated to 7.0.0
i tweaked my info.plist and changed
<key>FirebaseAppDelegateProxyEnabled</key><false/>
to
<key>FirebaseAppDelegateProxyEnabled</key>
<string>false</string>
strangely enough my notifications work in firebase_6.0.9 as i didnt upgrade to the newer one.
my appdelegate is:
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self)
//FirebaseApp.configure()
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
it is somewhat different to yours.
Firstly, if you use Firebase Cloud Messaging for notification, android will get the notification when app is open or closed.
But on iOS side, iOS is using APN's (Apple Push Notification)
.
*- You should try on real device. On iOS emulators, it's not stable to get notifications. On *
On your firebase console go to Settings > Cloud Messaging > iOS Application Configuration
then add your APN Identification Key from your Apple Developer panel. You can see on this document.
Also you should add "content_available": true
on your notification payload.
There is an example here:
{
"to": "/topics/topic_name",
"content_available": true,
"notification": {
"title": "TITLE TEXT",
"body": "BODY TEXT",
"content_available": true
},
"data": {
"body": "BODY TEXT",
"title": "TITLE TEXT",
"click_action": "FLUTTER_NOTIFICATION_CLICK"
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With