在 iOS 模拟器中收到 Firebase FCM 通知,但在真正的 iOS 设备上作为 GCM(?) 在 flutter 应用程序中收到

Firebase FCM notification received in iOS simulator but as GCM(?) on real iOS device in flutter app

编辑:根据 Firebase 支持

,它应该看起来像在设备日志中显示的那样

我正在通过 FCM 将推送通知添加到我的 Flutter 应用程序,但是 iOS 模拟器与我的 iPhone 5s 上的消息格式非常不同。 从 Firebase 控制台接收到 active/opened 应用程序的推送通知时。

问题:我需要做什么来确保真实设备以正确的格式接收消息?


从模拟器登录(iPhone XR,12.2)(在官方代码示例中看起来像):

    onMessage: {
    from: 123000000000,
    collapse_key: com.mydomainnamehere,
    notification: {
        body: Lorem ipsum,
        title: Title,
        e: 1,
        tag: campaign_collapse_key_9876543210011223344
    }
}


从真实设备登录(iPhone 5s,12.2)(在线找不到任何参考):

onMessage: {
    google.c.a.c_l: notif_name,
    google.c.a.e: 1,
    aps: {
        alert: {
            title: Title,
            body: Lorem ipsum
        }
    },
    gcm.n.e: 1,
    google.c.a.c_id: 9876543210011223344,
    google.c.a.udt: 0,
    gcm.message_id: 1234567800998877,
    google.c.a.ts: 1234567800
}



通知从 Firebase 控制台发送到所有设备,日志来自同一个通知(但我匿名了 id)。

设备和模拟器 运行 来自 Android Studio 的相同 Flutter 代码,同时。

我的 pubspec.yaml 部分涉及 FCM

  firebase_core: ^0.4.0+1
  firebase_auth: 0.11.1
  cloud_firestore: ^0.11.0+2
  firestore_ui: ^1.4.0
  firebase_messaging: ^5.0.2

软件和 SDK 版本

Flutter Channel 开发者,v1.8.4, Mac OS X 10.14.5, Android SDK 版本 28.0.3, Xcode 10.2.1, Android Studio 版本 3.4

Flutter 消息处理代码

void initState() {
    super.initState();

    if (Platform.isIOS) {
      iosSubscription = _fcm.onIosSettingsRegistered.listen((IosNotificationSettings settings) {
        print("FCM settings received: $settings");
      });

      _fcm.requestNotificationPermissions(IosNotificationSettings());
    }

    _fcm.configure(
      onMessage: (Map<String, dynamic> message) async {
        print("onMessage: $message");
      },
    );

    getFcmToken();
  }

  void getFcmToken() async {
    var token = await FirebaseMessaging().getToken();
    print("Token $token");
  }

我原以为 JSON 格式在模拟器和真实设备上是相同的。但真实设备甚至没有收到所有通知。

根据 Firebase 支持,我们应该无法在模拟器中获取推送通知,他们说上面的 gcm-format 确实是正确的。

解决方案是始终使用上一个问题的答案中所述的键值对

对于那些仍然为此苦苦挣扎的人来说,似乎有一个替代解决方案。 虽然数据的结构在各种条件下可能不同(iOS/Android 或 Real device/Simulator),但无论嵌套多深,数据的这些重要部分的键名称都被认为是唯一的:“title " 和 "body"。因此,提取那些 'title' 和 'body' 条目的值可能会解决问题。

//get title value from the message load (whether data or push)
String _title = _findFirstKeyValue(message, 'title');

下面是一个递归函数,用于从消息 Map 中获取第一个匹配条目。

  String _findFirstKeyValue(Map data, String targetKey) {
    for (final k in data.keys) {
      final v = data[k];

      if (v is Map) { // go deeper if the value is still a kind of Map
        final String _temp = _findFirstKeyValue(v, targetKey);
        if (_temp != '') return _temp;

      } else { // when the value is primitive Key-Value pair
        if (k.toString().toLowerCase() == targetKey.toLowerCase())  {
          return v.toString();
        }
      }
    }
    return '';
  }

请注意,如果您使用 data.forEach 而不是普通的 for loopreturn 将不会被触发。