Flutter - firebase FCM 消息根本不适用于 Testflight 发布版本 [英] Flutter - firebase FCM messages not working on Testflight release builds at all

查看:28
本文介绍了Flutter - firebase FCM 消息根本不适用于 Testflight 发布版本的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前言:

我的应用是基于 Flutter 的 - 但需要实现本机代码才能使 FCM 消息正常工作,请参阅下文了解更多详情

My App is Flutter based - but native code implementation is required to get FCM messages working, see below for more details

GitHub 问题 #154供参考.

我无法在 iOS 上获取 FCM 通知,特别是在我发布到 Testflight 的应用上.我已经被这个问题困住了一个星期,完全不知道如何继续.

I'm having immense trouble getting FCM notifications working on iOS, specifically on my app published to Testflight. I have been stuck on this problem for a week and have absolutely no idea how to proceed.

问题

使用 Xcode/Android Studio 在我的设备上使用调试/发布版本在本地运行时,会在后台、前台等接收通知.将完全相同的应用程序上传到 Testflight 时,而不是单个通知将通过 FCM 发送.

When running locally using debug/release builds on my devices using Xcode/Android Studio, notifications are received in the background, foreground, etc. When uploading the exact same app to Testflight, not a single notification will come through via FCM.

这很重要,因为 FCM 提供 VoIP 通知,但在 Testflight 上没有收到这些通知,这非常令人沮丧

问题&解决方案?

我发现了 2 个问题(此处 & 这里),两者似乎都表明这是一个 APNS 证书问题(APNS -> Firebase).我重新创建了我的证书并将其添加到 Firebase 控制台(对所有证书生成操作使用相同的 .csr 文件)

There are 2 questions I found (here & here), both seemed to indicate it is a APNS certificate problem (APNS -> Firebase). I have recreated my certificate and added it to the Firebase console (using the same .csr file for all certificate generating operations)

设置/配置:

  • APNS密钥生成&添加到 Firebase

  • APNS Key generated & added to Firebase

能力:

尝试过:

<key>FirebaseAppDelegateProxyEnabled</key>
<string>NO</string>

与:

<key>FirebaseAppDelegateProxyEnabled</key>
<string>0</string>

并带有:

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

  • 背景模式:
  •     <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>
            <string>remote-notification</string>
        </array>
    

    教程/来源:

    Swift 代码:(目标 >=10.0)

    Swift Code: (targeting >=10.0)

    
    import UIKit
    import CallKit
    import Flutter
    import Firebase
    import UserNotifications
    import GoogleMaps
    import PushKit
    import flutter_voip_push_notification
    import flutter_call_kit
    
    @UIApplicationMain
    @objc class AppDelegate: FlutterAppDelegate, PKPushRegistryDelegate {
        override func application(
            _ application: UIApplication,
            didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
        ) -> Bool {
            
            // run firebase app
            FirebaseApp.configure()
            
            // setup Google Maps
            GMSServices.provideAPIKey("google-maps-api-key")
            
            // register notification delegate
            UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
            
            GeneratedPluginRegistrant.register(with: self)
            
            // register VOIP
            self.voipRegistration()
            
            // register notifications
            application.registerForRemoteNotifications();
            return super.application(application, didFinishLaunchingWithOptions: launchOptions)
        }
        
        // Handle updated push credentials
        public func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) {
            // Process the received pushCredentials
            FlutterVoipPushNotificationPlugin.didUpdate(pushCredentials, forType: type.rawValue);
        }
        
        // Handle incoming pushes
        public func pushRegistry(_ registry: PKPushRegistry,
                                 didReceiveIncomingPushWith payload: PKPushPayload,
                                 for type: PKPushType,
                                 completion: @escaping () -> Swift.Void){
            
            FlutterVoipPushNotificationPlugin.didReceiveIncomingPush(with: payload, forType: type.rawValue)
            
            let signalType = payload.dictionaryPayload["signal_type"] as! String
            if(signalType == "endCall" || signalType == "rejectCall"){
                return
            }
            
            let uuid = payload.dictionaryPayload["session_id"] as! String
            let uID = payload.dictionaryPayload["caller_id"] as! Int
            let callerName = payload.dictionaryPayload["caller_name"] as! String
            let isVideo = payload.dictionaryPayload["call_type"] as! Int == 1;
            FlutterCallKitPlugin.reportNewIncomingCall(
                uuid,
                handle: String(uID),
                handleType: "generic",
                hasVideo: isVideo,
                localizedCallerName: callerName,
                fromPushKit: true
            )
            completion()
        }
        
        // Register for VoIP notifications
        func voipRegistration(){
            // Create a push registry object
            let voipRegistry: PKPushRegistry = PKPushRegistry(queue: DispatchQueue.main)
            // Set the registry's delegate to self
            voipRegistry.delegate = self
            // Set the push type to VoIP
            voipRegistry.desiredPushTypes = [PKPushType.voIP]
        }
    }
    
    public func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        if #available(iOS 14.0, *) {
            completionHandler([ .banner, .alert, .sound, .badge])
        } else {
            completionHandler([.alert, .sound, .badge])
        }
    }
    
    func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        print(deviceToken)
        Messaging.messaging().apnsToken = deviceToken;
    }
    
    

    Flutter main.dart

    void main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await Firebase.initializeApp();
      await initializeDateFormatting();
      setupLocator();
      var fcmService = locator<FCMService>();
    
      FirebaseMessaging.onBackgroundMessage(FCMService.handleFirebaseBackgroundMessage);
      FirebaseMessaging.onMessage.listen((event) {
        print("Foreground message");
        Fluttertoast.showToast(msg: "Received onMessage event");
        FCMService.processCallNotification(event.data);
      });
      FirebaseMessaging.onMessageOpenedApp.listen((event) {
        print("On message opened app");
        Fluttertoast.showToast(msg: "Received onMessageOpenedAppEvent");
        FCMService.handleInitialMessage(event);
      });
      FirebaseMessaging.instance.getInitialMessage().then((value) {
        Fluttertoast.showToast(msg: "Received onLaunch event");
        if (value != null) {
          FCMService.handleInitialMessage(value);
        }
      });
    
      initConnectyCube();
      runApp(AppProviders());
    }
    

    FCMService.dart

      // handle any firebase message
      static Future<void> handleFirebaseBackgroundMessage(RemoteMessage message) async {
        print("Received background message");
        Fluttertoast.showToast(msg: "Received Firebase background message");
        await Firebase.initializeApp();
        setupLocator();
        var fcmService = locator<FCMService>();
        fcmService.init();
    
        _handleMessage(message, launchMessage: true);
      }
    

    测试:

    测试是在 2 部实体 iPhone(6 和 8)上完成的.在使用(调试和发布)模式直接从 Mac(Android Studio 和 XCode)构建时,两者都与 Firebase FCM 一起使用.从 TestFlight 下载相同的文件时,两者都不起作用.

    Testing is done on 2 physical iPhones (6s & 8). Both work with Firebase FCM when building directly from Mac (Android Studio & XCode) using (debug & release) modes. Neither works when downloading the same from TestFlight.

    如果有人能提供有关错误配置、设置错误或缺少/不正确的 Swift 代码,或者仅仅是错误或遗漏的见解,我们将不胜感激.

    If any can provide insight into a misconfiguration, an error in setup or missing/incorrect Swift code, or simply a mistake or omission, it would be much appreciated.

    推荐答案

    前言:是我的问题.

    TL;DR仅将 CubeEnvironment 的 1 个引用更改为 PRODUCTION.

    TL;DR changed only 1 reference of CubeEnvironment to PRODUCTION.

    有多个位置可以更改CubeEnvironment:

    使用建议,最好将其添加到CallManagerService"的init() 方法中:

    Suggestion to use, even better to add this in your "CallManagerService"'s init() method:

        bool isProduction = bool.fromEnvironment('dart.vm.product');
        parameters.environment = isProduction ? CubeEnvironment.PRODUCTION : CubeEnvironment.DEVELOPMENT;
    


    调试(过程):调试过程(对 Swift 和 XCode 有点陌生)本来可以更好.我考虑了各种配置文件、aps-environment 设置等.


    Debugging (process): The debugging process (being somewhat unfamiliar with Swift & XCode) could have been better. I considered various provisioning profiles, aps-environment settings, etc.

    由于该问题仅发生在 Testflight,它使调试更具挑战性和耗时,因为上传调试版本有其自身的一系列问题

    Since the issue only occurred on Testflight, it made debugging alot more challenging and time consuming as uploading a debug build had its own set of issues

    最后我添加了一堆日志,其中最重要的是 CB-SDK 调试入口(收到通知时):

    Finally I added a bunch of logging, the one that was crucial was the CB-SDK debug entry (when a notification is received):

    [
      {
        "subscription": {
          "id": sub id,
          "_id": "insert sub id",
          "user_id": cube_user_id,
          "bundle_identifier": "insert bundle id",
          "client_identification_sequence": "insert client id",
          "notification_channel_id": 6,
          "udid": "insert-uuid",
          "platform_id": 1,
          "environment": "development",
          "notification_channel": {
            "name": "apns_voip"
          },
          "device": {
            "udid": "insert-uuid",
            "platform": {
              "name": "ios"
            }
          }
        }
      }
    ]
    

    特别是以下条目.

    environment": "development
    

    这是因为 APS 使用了 2 个不同的推送通知环境,每个环境都有自己的证书(证书被分配给推送通知可以来自的唯一 URL).这个,aps-environment 设置为 'production(在开始上传之前查看上传存档屏幕)但我正在接收 development 环境通知 - 需要修复.

    This is due to APS used 2 different push notification environments, each with its own certificates (certificate is assigned to unique URL's where push notifications can come from). This, aps-environment is set to 'production (see on upload Archive screen right before you start uploading) but I'm receiving development environment notifications - that needed fixing.

    查看我的代码,我终于找到了问题(并修复了上面提到的问题).

    Reviewing my code, I finally found the issue (and fix mentioned above).

    这篇关于Flutter - firebase FCM 消息根本不适用于 Testflight 发布版本的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆