Flutter Push Notifications:无法在后台或应用关闭时接收通知

Posted

技术标签:

【中文标题】Flutter Push Notifications:无法在后台或应用关闭时接收通知【英文标题】:Flutter Push Notifications: Unable to receive notifications in background or when app is closed 【发布时间】:2020-11-23 10:14:18 【问题描述】:

我正在为 androidios 开发一个颤振应用程序。它有通知,所以我确实实现了firebase_messaging API。我正在通过设备 ID 向某些设备发送通知,并向topics 发送通知。

我正在测试topics 通知发送,它在 Android 中可以 100% 正常工作。我按照上面提供的链接中的指南,也实现了 iOS 设置。但是在 iOS 中,当通知被发送时,只有当它在前台时才会被应用程序接收。这意味着,只能通过onMessage。如果应用程序处于后台或关闭状态,我看不到任何通知(我在控制台中打印它)。但是当我重新打开应用程序时,通知会被打印出来。

以下是我的通知注册码

    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)
      );
    

下面是我的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>

下面是 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)
    

正如一些人在其他 SO 答案中所建议的那样,我从 AppDelegate.swift 代码中删除了以下部分并尝试了,但同样的问题仍然存在。

if #available(iOS 10.0, *) 
      UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
    

我已将苹果密钥文件上传到 Firebase 项目 cloud messaging 部分,如指南中所述。

下面是我发送通知的 JSon 代码


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

我的登录能力如下

我是 iOS 新手,不知道发生了什么。我想就像在 Android 中一样,当应用处于后台或关闭时,通知会自动出现在通知栏中。

更新

根据@nandish 的建议,我将AppDelegate.swift 文件更改如下

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) 

     

然后我得到了以下错误

UNUserNotificationCenter' is only available in iOS 10.0 or newer
        func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) 

更新

在前台,当发出通知时,我会收到来自应用程序的以下响应。这也只是在 iPhone 模拟器中,而不是在真实设备中。

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

【问题讨论】:

您可以截屏一下您添加到目标的功能吗? @Honey:抱歉回复延迟。我已经添加了截图。请检查。 @Honey:我似乎也没有收到真实设备的通知。我的测试设备是 iPhone 6。 看起来不错。有时只是取消选中并再次检查它们可能会解决它。另外,您何时取消注册设备令牌?也许您正在做一些在后台注销用户的操作 顺便说一句,您的真实设备没有收到通知是什么意思?推送通知仅发送到真实设备。模拟器无法使用 APN 创建令牌...所以只能使用真实设备进行测试 【参考方案1】:

首先,如果您使用 Firebase Cloud Messaging 进行通知,Android 会在应用打开或关闭时收到通知。 但在 iOS 端,iOS 使用的是APN's (Apple Push Notification)

*- 您应该在真实设备上尝试。在 iOS 模拟器上,获取通知不稳定。开 *

在您的 Firebase 控制台上转到 Settings &gt; Cloud Messaging &gt; iOS Application Configuration,然后从您的 Apple 开发人员面板添加您的 APN 标识密钥。你可以在this document上看到。

您还应该在通知负载中添加"content_available": true

这里有一个例子:


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

【讨论】:

感谢您的回复。好吧,我只是尝试使用真实设备,然后注意到我根本没有收到任何通知。但是昨天我在真实设备中收到通知,当它在前台时。然后我使用了content_available=true 并没有好。我认为我已经正确上传了 APN,否则我根本不应该收到任何通知,不是吗?当应用程序处于前台时,我会收到模拟器通知。 好的,我明白了,其实我不知道为什么。我在我的手机上试过,当应用程序关闭时我也无法收到通知。也许问题出在 firebase 消息包上。 "content_available": true 表示它是静默通知。请删除该标签。 谢谢 Jasmit,我不知道。抱歉信息不正确。【参考方案2】:

对于后台通知,您可以尝试添加 “后台模式” 功能,方法是在目标项目的 “签名和功能”下单击 “+ 功能” " 选项卡并按照以下苹果文档中的建议启用 远程通知

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

您还应该在 AppDelegate.swift 中添加如下内容:

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) 

     

【讨论】:

感谢您的回复,但这给出了错误。基本上它说您的方法仅适用于 iOS 10 及更高版本。我已经用这个更新了我的问题.. 另外,我似乎没有收到真实设备的通知。我的测试设备是 iPhone 6。 您是否在调试模式下通过连接测试通知?【参考方案3】:

当他们在 firebase_messaging 6.0.16 中发现问题时,我遇到了一个非常相似的问题,现在它已更新到 7.0.0

我调整了我的 info.plist 并更改了

<key>FirebaseAppDelegateProxyEnabled</key><false/>

<key>FirebaseAppDelegateProxyEnabled</key>
<string>false</string>

奇怪的是,我的通知在 firebase_6.0.9 中工作,因为我没有升级到较新的。

我的 appdelegate 是:

@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)
  
  

和你的有些不同。

【讨论】:

成功了,非常感谢!!我像您一样更改 info.plist 并更改 firebase_messaging 版本 6.0.9 及其工作。在此之前我使用版本 7.0.3【参考方案4】:

您是否尝试过强制转换传递给 onMessage 回调的消息数据,

data = Map<String, dynamic>.from(message['data']);

【讨论】:

以上是关于Flutter Push Notifications:无法在后台或应用关闭时接收通知的主要内容,如果未能解决你的问题,请参考以下文章

laravel-push-notification 在响应正文中返回 html 标记

重复本地通知在 react-native-push-notification 中不起作用

:自定义push notification sound

资料整理:基于node push server实现push notification

在Push Notification Android上下载文件

react-native-push-notification - 本地通知不适用于 Android