iOS 模拟器或物理设备未收到 FCM 数据消息

Posted

技术标签:

【中文标题】iOS 模拟器或物理设备未收到 FCM 数据消息【英文标题】:FCM data messages not being received by iOS Simulator or physical device 【发布时间】:2021-11-02 10:02:46 【问题描述】:

我正在进行的一个项目需要使用 FCM 推送通知和消息来进行 VoIP 控制等。

问题:

我的 ios 物理设备接收推送通知,但在应用程序处于后台或关闭时在前台时。此外,它不会收到任何 fcm 消息(数据)通知,例如只有数据而没有通知标题/正文的消息,即 VoIP 状态消息。


我的设置步骤如下(详细设置和我遵循的一般流程可以在here找到):

    注册 (Info.plist)(见here)

    下载并使用 Xcode 安装 GoogleService-Info.plist(参见 here)

    创建 APNS 密钥并启用推送通知并将 .p8 文件上传到 Firebase(见here)

    修改Swift代码:

AppDelegate.swift代码:

import UIKit
import Flutter
import Firebase // this is added, and (see further down)

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate 
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool 
    FirebaseApp.configure() //add this before the code below
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  

    添加 功能到 iOS

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>BGTaskSchedulerPermittedIdentifiers</key>
    <array>
        <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
    </array>
    ...
    <key>NSCameraUsageDescription</key>
    <string>Allows taking a self-portrait profile image or sending a photo while chating</string>
    <key>NSLocationAlwaysUsageDescription</key>
    <string>Allows using your location to make determining country &amp; location picking easier (optional)</string>
    <key>NSMicrophoneUsageDescription</key>
    <string>Allows using micrphone to chat with someone when making a call</string>
    <key>NSPhotoLibraryUsageDescription</key>
    <string>Allows opening files from gallery</string>
    <key>UIBackgroundModes</key>
    <array>
        <string>audio</string>
        <string>bluetooth-central</string>
        <string>external-accessory</string>
        <string>fetch</string>
        <string>location</string>
        <string>processing</string>
        <string>remote-notification</string>
        <string>voip</string>
    </array>
    <key>UILaunchStoryboardName</key>
    <string>LaunchScreen</string>
    <key>UIMainStoryboardFile</key>
    <string>Main</string>
    <key>FirebaseAppDelegateProxyEnabled</key>
    <false/>
    <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>

注意:无法启用here 所示的背景模式,而是使用一组复选框启用它们以启用Background Fetch 等。

    FCM - 收听和显示以及使用某些通知(显示)服务(例如awesome notifications)的通知/消息

实现遵循这些guidelines:

前台消息:

FirebaseMessaging.onMessage.listen((RemoteMessage message) 
  print('Got a message whilst in the foreground!');
  ...
);

背景信息:

Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async 
  await Firebase.initializeApp();

  print("Handling a background message: $message.messageId");


void main() 
  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);
  runApp(MyApp());

问题扩展:

在调试时,如果 iOS 应用程序处于前台/后台,并且向设备发送了测试通知或有效的 VoIP 呼叫(FCM 数据消息),则该应用程序永远不会收到或(也不会命中所需的断点)。

什么会导致应用/iOS 收不到这些 FCM 消息?


从 Firebase 云功能服务发送的示例 VoIP 消息:

// build notification on liked status
const payload = 
    token: fcmToken,
    data: 
        uid: context.auth.uid,
        room_id: roomId,
        ...
    ,
    android: 
        priority: 'high',
        ttl: 0,
        notification: 
            priority: 'max',
            defaultSound: true,
            defaultVibrateTimings: true,
            sticky: true,
            clickAction: "FLUTTER_NOTIFICATION_CLICK",
        
    ,
    notification: 
        title: `Incoming call from $name`,
        body: `Accept/Reject call`,
        // icon: 'your-icon-url',                   // Add profile image URL here if necessary
        // clickAction: 'FLUTTER_NOTIFICATION_CLICK' // required only for onResume or onLaunch callbacks
    ,
    apns: 
        payload: 
            aps: 
                category: "NEW_MESSAGE_CATEGORY",
                contentAvailable: true,
            
        
    ,
    headers: 
        "apns-push-type": "background",
        "apns-priority": "5", // Must be `5` when `contentAvailable` is set to true.
        "apns-topic": "io.flutter.plugins.firebase.messaging", // bundle identifier
    ,
;

await admin.messaging().send(payload);

【问题讨论】:

我又看了你的3个问题,更新了我的答案。 【参考方案1】:

原始答案(更通用/对更多人有用):

FCM 在 iOS 模拟器上不起作用,所以问题解决了一半。对于物理设备,请看一些debugging steps我在我工作的库上详细写的。

在 iOS 上,推送通知有多种方式可能出错。当您说:the app never receives 时,您的意思是您的 Flutter 应用程序没有收到消息吗?您的设备仍可以接收它们。

在您的 Mac 上打开 Console.app,然后开始记录您的物理设备。过滤dasd进程,你可以看到推送通知相关的日志,看看你的设备是否拒绝了推送通知并且没有将其发送到你的应用程序。很可能是您的信息结构存在问题。 你也可以尝试在Flutterfire firebase_messaging iOS 代码里面调试iOS 端的didReceiveRemoteNotification 方法。 表示应用已收到消息。

让我具体回答每个问题/疑虑 (3):

    我的 iOS 物理设备会收到推送通知,但仅在应用处于后台或关闭时而不是在前台时

所以你想在前台显示通知?你需要实现userNotificationCenter(_:willPresent:withCompletionHandler:),例如在Swift中:

    public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) 
        if #available(iOS 14.0, *) 
            completionHandler(.banner)
         else 
            completionHandler(.alert)
        
    

为了在这方面为您提供更多帮助,您需要设置您的委托。在上面实现的方法中放置一个断点以查看它实际上被调用了。

在 Swift 中:UNUserNotificationCenter.current().delegate = self; 在 Objective-C 中:UNUserNotificationCenter.currentNotificationCenter.delegate = self;
    此外,它根本不会收到任何 fcm 消息(数据)通知,例如只有数据而没有通知标题/正文的消息,即 VoIP 状态消息。

如果不设置通知字段,则需要设置优先级为5,推送类型为backgroundcontentAvailabletrue。不幸的是,您在 firebase 中使用了错误的 headers 字段。 apns 对象应如下所示,其中标头位于 apns 内,因为这些是 apns 特定标头:

    apns: 
        headers: 
            "apns-push-type": "background",
            "apns-priority": "5", // Must be `5` when `contentAvailable` is set to true.
            "apns-topic": "io.flutter.plugins.firebase.messaging", // bundle identifier
        ,
        payload: 
            aps: 
                category: "NEW_MESSAGE_CATEGORY",
                contentAvailable: true,
            
        
    

如果消息结构错误,您仍然可能在设备上收到错误消息,例如,告诉您优先级为 10(如果未设置,则默认为 10)。由于不会按照文档传递后台消息(无通知),因此您应该在Console.app 中看到:

CANCELED: com.apple.pushLaunch.com.example.my-example-app-bundle-id:3D8BB6 at priority 10 <private>!

另外,通知的 POST 请求应该包含值为 background 的 apns-push-type 头域和值为 5 的 apns-priority 域。 - Pushing Background Updates to Your App

    在调试时,如果 iOS 应用程序处于前台/后台,并且向设备发送了测试通知或有效的 VoIP 呼叫(FCM 数据消息),则应用程序永远不会收到或(也不会命中所需的断点)。什么会导致应用/iOS 收不到这些 FCM 消息?

这与 #2 相同。

【讨论】:

感谢您花时间回答。在第一点上,我不完全确定我应该搜索什么,但在查看dasd 或应用程序流程时,我没有看到任何提及或火力或通知或消息等。关于结构,我遵循了所有建议的文档(请参阅我使用的来源)。关于第二点,你有一个快速的例子给我吗?我看到提供的链接中的示例仅显示 .h.m 文件,但没有 .swift 示例(我不熟悉 swift)。非常感谢 您必须在 Xcode 中打开您的应用程序(xed ios 在 Flutter 项目目录中时)并通过那里运行您的应用程序,导航到位于 Objective- 中的 firebase_messaging iOS 代码中的文件实现didReceiveRemoteNotification 并在方法实现中放置断点的C。如果该断点被触发,那么并不是设备没有收到消息。您可能会在 Console.app 中获得有关这些错误的更多信息。它不会是 dasd 中记录的“Firebase”消息,而只是 APN/推送消息,因为 Firebase 在 iOS 上使用 APN。 您也可以在Console.app的搜索栏中搜索com.apple.pushLaunch【参考方案2】:

呃,试试AppDelegate

override func application(_ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool 
  // ADD THIS LINE
  UNUserNotificationCenter.current().delegate = self
        
  GeneratedPluginRegistrant.register(with: self)
  return super.application(application, didFinishLaunchingWithOptions: launchOptions)


// ADD THIS FUNCTION
override func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) 
  // Need to do this or app will eat the notification if app is in foreground
  completionHandler([.alert, .badge, .sound])

编辑:请注意 Ben 的回答仍然适用,并且推送在模拟器中不起作用,您必须在物理设备上运行它。

【讨论】:

以上是关于iOS 模拟器或物理设备未收到 FCM 数据消息的主要内容,如果未能解决你的问题,请参考以下文章

FCM iOS 项目未收到通知 - FCM 控制台显示成功但设备未收到

模拟器或物理设备上的“未安装应用程序”android? [复制]

模拟器上未收到 Firebase 消息

FCM 未收到通知消息

通过 FCM 发送时未收到推送通知,但在 IOS 上通过 APN 发送时收到

未收到 Flutter FCM IOS 静默(仅数据)通知