Flutter Push Notifications: Unable to receive notifications in background or when app is closed

三世轮回 提交于 2020-08-18 16:57:39

问题


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}

回答1:


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"
  }
}



回答2:


For Background notifications , you can try adding "Background Modes" capability in by clicking on "+ Capability" on your target project under "Signing & Capabilities" tab and enable Remote notifications as suggested in below apple document.

https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app

Also in your AppDelegate.swift you should added as below:

class AppDelegate: FlutterAppDelegate , UNUserNotificationCenterDelegate {
      override func application(_ application: UIApplication,
          didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
       ....
       UNUserNotificationCenter.current().delegate = self
       ....
    }
    ....

    // 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) {

     }
}


来源:https://stackoverflow.com/questions/63227853/flutter-push-notifications-unable-to-receive-notifications-in-background-or-whe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!