FCM 后台通知适用于 Android;不在 iOS 中

Pea*_*Gen 6 android ios firebase flutter firebase-cloud-messaging

我正在开发一个 flutter 应用程序Firebase messaging。该应用程序适用于 iOS 和 Android。

\n

在 Android 版本中,我可以很好地获取数据消息,并且 Firebase Messaging 后台监听器运行良好。每次发送消息时都会触发后台侦听器。

\n

然而在 iOS 中,后台监听器永远不会被触发。但是,如果我发送包含部分的推送通知notification,则 SDK 将显示默认通知,但后台消息侦听器中仍然没有任何反应。

\n

阅读了很多问题,我发现很多人都遇到过这个问题。下面是我的代码。

\n

主dart

\n
void main() async {\n  WidgetsFlutterBinding.ensureInitialized();\n\n  await Firebase.initializeApp();\n\n  FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler);\n\n  FirebaseMessaging.instance\n        .getInitialMessage()\n        .then((RemoteMessage? message) {\n      developer.log("REMOTE MESSAGE");\n      if (message != null) {\n        developer.log(message.data.toString());\n      }\n    });\n\n  FirebaseMessaging.onMessage.listen((RemoteMessage message) async {\n    RemoteNotification? notification = message.notification;\n    AndroidNotification? android = message.notification?.android;\n    developer.log("REMOTE MESSAGE LISTENER");\n    if (message.data["data_type"] == "TEXT") {\n      await AwesomeNotifications().createNotification(\n        content: NotificationContent(\n            id: UniqueKey().hashCode,\n            groupKey: message.data["senderUid"],\n            channelKey: \'basic_channel\',\n            title: message.data["title"],\n            body: message.data["body"],\n            summary: message.data["body"], // Anything you want here\n            notificationLayout: NotificationLayout.Messaging,\n            displayOnBackground: true,\n            displayOnForeground: true),\n      );\n    } else if (message.data["data_type"] == "IMAGE") {\n      await AwesomeNotifications().createNotification(\n        content: NotificationContent(\n            id: UniqueKey().hashCode,\n            groupKey: message.data["senderUid"],\n            channelKey: \'basic_channel\',\n            title: message.data["title"],\n            body: Emojis.art_framed_picture + " " + message.data["body"],\n            summary: message.data["body"], // Anything you want here\n            notificationLayout: NotificationLayout.Messaging,\n            displayOnBackground: true,\n            displayOnForeground: true),\n      );\n    }\n  });\n\n  //Request permission for firebase messaging\n\n  NotificationSettings settings =\n      await FirebaseMessaging.instance.requestPermission(\n    alert: true,\n    announcement: false,\n    badge: true,\n    carPlay: false,\n    criticalAlert: false,\n    provisional: false,\n    sound: true,\n  );\n\n  print(\'User granted permission: ${settings.authorizationStatus}\');\n\n  /// Update the iOS foreground notification presentation options to allow\n  /// heads up notifications.\n  await FirebaseMessaging.instance.setForegroundNotificationPresentationOptions(\n    alert: true,\n    badge: true,\n    sound: true,\n  );\n\n  AwesomeNotifications().initialize(\'resource://drawable/logo\', [\n    NotificationChannel(\n        channelGroupKey: \'basic_tests\',\n        channelKey: \'basic_channel\',\n        channelName: \'Basic notifications\',\n        channelDescription: \'Notification channel for basic tests\',\n        defaultColor: Color(0xFF9D50DD),\n        ledColor: Colors.white,\n        importance: NotificationImportance.High),\n  ]);\n\n  runApp(MultiProvider(\n    child: MyApp(),\n  ));\n}\n
Run Code Online (Sandbox Code Playgroud)\n

AppDeligate.swift

\n
import UIKit\nimport Flutter\nimport GoogleMaps\nimport FirebaseMessaging\n\n@UIApplicationMain\n@objc class AppDelegate: FlutterAppDelegate {\n  override func application(\n    _ application: UIApplication,\n    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?\n  ) -> Bool {\n      GMSServices.provideAPIKey("xxxxxxx-xxxx")\n    GeneratedPluginRegistrant.register(with: self)\n    return super.application(application, didFinishLaunchingWithOptions: launchOptions)\n  }\n    \n    override func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {\n\n       Messaging.messaging().apnsToken = deviceToken\n       super.application(application, didRegisterForRemoteNotificationsWithDeviceToken: deviceToken)\n     }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n

pubspec.yaml

\n
name: project\ndescription: A new Flutter project.\n\nversion: 1.0.0+1\n\nenvironment:\n  sdk: ">=2.12.0 <3.0.0"\n\n\n\ndependencies:\n  intl: ^0.17.0\n\n  firebase_auth: ^3.1.0\n  firebase_core: ^1.6.0\n  firebase_messaging: ^11.4.1\n  cloud_firestore:  ^3.1.9\n  firebase_storage: ^10.2.8\n  awesome_notifications: ^0.6.21\n\ndependency_overrides:\n  firebase_messaging_platform_interface: ^3.5.1\n  firebase_crashlytics_platform_interface: 3.1.13\n  cloud_firestore_platform_interface: 5.4.13\n  firebase_auth_platform_interface: 6.1.11\n  firebase_storage_platform_interface: 4.0.14\n  cloud_functions_platform_interface: 5.0.21\n  firebase_analytics_platform_interface: 3.0.5\n  firebase_remote_config_platform_interface: 1.0.5\n  firebase_dynamic_links_platform_interface: 0.2.0+5\n  firebase_performance_platform_interface: 0.1.0+5\n  firebase_app_installations_platform_interface: 0.1.0+6\n\ndev_dependencies:\n  flutter_test:\n    sdk: flutter\n\n# For information on the generic Dart part of this file, see the\n# following page: https://dart.dev/tools/pub/pubspec\n# The following section is specific to Flutter.\nflutter:\n  # The following line ensures that the Material Icons font is\n  # included with your application, so that you can use the icons in\n  # the material Icons class.\n  uses-material-design: true\n\n  # To add assets to your application, add an assets section, like this:\n  assets:\n    - assets/graphics/\n    - assets/icons_chat/\n    - assets/lottie/\n \n
Run Code Online (Sandbox Code Playgroud)\n

信息表

\n
<?xml version="1.0" encoding="UTF-8"?>\n<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n<plist version="1.0">\n<dict>\n    <key>CFBundleDevelopmentRegion</key>\n    <string>$(DEVELOPMENT_LANGUAGE)</string>\n    <key>CFBundleExecutable</key>\n    <string>$(EXECUTABLE_NAME)</string>\n    <key>CFBundleIdentifier</key>\n    <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>\n    <key>CFBundleInfoDictionaryVersion</key>\n    <string>6.0</string>\n    <key>CFBundleName</key>\n    <string>customer</string>\n    <key>CFBundlePackageType</key>\n    <string>APPL</string>\n    <key>CFBundleShortVersionString</key>\n    <string>$(FLUTTER_BUILD_NAME)</string>\n    <key>CFBundleSignature</key>\n    <string>????</string>\n    <key>CFBundleVersion</key>\n    <string>$(FLUTTER_BUILD_NUMBER)</string>\n    <key>LSRequiresIPhoneOS</key>\n    <true/>\n    <key>UILaunchStoryboardName</key>\n    <string>LaunchScreen</string>\n    <key>UIMainStoryboardFile</key>\n    <string>Main</string>\n    <key>UISupportedInterfaceOrientations</key>\n    <array>\n        <string>UIInterfaceOrientationPortrait</string>\n        <string>UIInterfaceOrientationLandscapeLeft</string>\n        <string>UIInterfaceOrientationLandscapeRight</string>\n    </array>\n    <key>UISupportedInterfaceOrientations~ipad</key>\n    <array>\n        <string>UIInterfaceOrientationPortrait</string>\n        <string>UIInterfaceOrientationPortraitUpsideDown</string>\n        <string>UIInterfaceOrientationLandscapeLeft</string>\n        <string>UIInterfaceOrientationLandscapeRight</string>\n    </array>\n    <key>UIViewControllerBasedStatusBarAppearance</key>\n    <false/>\n    <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>\n    <string>Use your device location to find nearby sellers</string>\n    <key>NSLocationAlwaysUsageDescription</key>\n    <string>Use your device location to find nearby sellers</string>\n    <key>NSLocationWhenInUseUsageDescription</key>\n    <string>Use your device location to find nearby sellers</string>\n    <key>NSPhotoLibraryUsageDescription</key>\n    <string>Take image from your gallery</string>\n    <key>NSCameraUsageDescription</key>\n    <string>Take image from your gallery</string>\n    <key>NSMicrophoneUsageDescription</key>\n    <string>Take image from your gallery</string>\n    <key>UIBackgroundModes</key>\n    <array>\n        <string>fetch</string>\n        <string>remote-notification</string>\n    </array>\n    <key>GoogleUtilitiesAppDelegateProxyEnabled</key>\n    <false/>\n    <key>FirebaseAppDelegateProxyEnabled</key>\n    <false/>\n    <key>CADisableMinimumFrameDurationOnPhone</key>\n    <true/>\n</dict>\n</plist>\n
Run Code Online (Sandbox Code Playgroud)\n

正如你在这里看到的,我也启用了Background FetchRemote Notifications

\n

在为 iOS 设置 firebase 设置时,我已按照此处的设置进行操作 - https://firebase.flutter.dev/docs/messaging/apple-integration/#3-generate-a-provisioning-profile。这意味着向 Firebase 注册 APN 密钥、注册应用程序标识符(XCode 生成了正确的标识符并且我正在使用它),甚至生成了预配置配置文件(但是我使用的是 XCode 托管预配置配置文件)。无论如何我没有生成任何特定的证书,因为它已经由 XCode 完成了。

\n

下面是我的flutter doctor结果

\n
Doctor summary (to see all details, run flutter doctor -v):\n[\xe2\x9c\x93] Flutter (Channel stable, 3.0.1, on macOS 12.4 21F79 darwin-arm, locale\n    en-LK)\n[\xe2\x9c\x93] Android toolchain - develop for Android devices (Android SDK version 31.0.0)\n[!] Xcode - develop for iOS and macOS (Xcode 13.4.1)\n    ! CocoaPods 1.10.1 out of date (1.11.0 is recommended).\n        CocoaPods is used to retrieve the iOS and macOS platform side\'s plugin\n        code that responds to your plugin usage on the Dart side.\n        Without CocoaPods, plugins will not work on iOS or macOS.\n        For more info, see https://flutter.dev/platform-plugins\n      To upgrade see\n      https://guides.cocoapods.org/using/getting-started.html#installation for\n      instructions.\n[\xe2\x9c\x93] Chrome - develop for the web\n[\xe2\x9c\x93] Android Studio (version 2021.1)\n[\xe2\x9c\x93] VS Code (version 1.67.2)\n[\xe2\x9c\x93] Connected device (3 available)\n[\xe2\x9c\x93] HTTP Host Availability\n
Run Code Online (Sandbox Code Playgroud)\n

这是我的 JSON 通知数据

\n
"message": {\n\n    "token": recieverFcm,\n    "data": {\n        "title": senderName,\n        "body": message,\n        "chatRoomId": chatRoomId,\n        "sender_profile_pic": senderProfilePic,\n        "senderUid": senderUid,\n        "data_type": messageType,\n        "click_action": "OPEN_CHAT_ROOM"\n    },\n    "android": {\n        "priority": "high"\n    },\n    "apns": {\n        "payload": {\n            "aps": {\n                "category": "OPEN_CHAT_ROOM",\n                "sound": "enable",\n                "content-available": 1,\n            },\n            "data": {\n                "title": senderName,\n                "body": message,\n                "chatRoomId": chatRoomId,\n                "sender_profile_pic": senderProfilePic,\n                "senderUid": senderUid,\n                "data_type": messageType,\n                "click_action": "OPEN_CHAT_ROOM"\n            },\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

在上面的 Json 中,我有 2 个data部分仅用于测试。我已经测试过,删除其中任何一个都不会产生任何影响。

\n

我该如何解决这个问题?

\n

Kau*_*dru 0

https://developer.apple.com/account/resources/authkeys/list

Please go to this link.. Generate a key

关键页面

Then generate a new key. select Apple push notification

创建新密钥

Once you create a key you will get a secret and key id. Take a note of these values. Go to firebase console. In project settings you will find cloud messaging on top

云消息传递

In the bottom most section you will see iOS configuration and an option to add the APN key details. Please add your key secret and key ID here and save it.

Edit

Add priority in apns

"headers": {
         "apns-priority": "5",
       },
Run Code Online (Sandbox Code Playgroud)

and enable background processing in Xcode

Edit 1:

If things appear to look normal in the log but you're still not receiving notifications, try turning off the Notifications switch in Settings, and then turn it back on. That will try to re-establish the device's persistent connection with APNs

Some more technical info here https://developer.apple.com/library/archive/technotes/tn2265/_index.html#:~:text=If%20things%20appear%20to%20look,device's%20persistent%20connection%20with%20APNs.

Also please remove content available as that will make the notification available only once per day. Please check the document above