【发布时间】:2021-12-04 02:48:32
【问题描述】:
前言:
我的应用是基于 Flutter 的 - 但需要原生代码实现才能使 FCM 消息正常工作,请参阅下文了解更多详情
GitHub问题#154供参考。
我在获取 FCM 通知在 iOS 上工作时遇到了巨大的麻烦,特别是在我发布到 Testflight 的应用程序上。我已经被这个问题困扰了一个星期,完全不知道如何继续。
问题
当使用 Xcode/Android Studio 在我的设备上使用调试/发布版本在本地运行时,会在后台、前台等中收到通知。将完全相同的应用程序上传到 Testflight 时,不是单个通知将通过 FCM 发送。
这是至关重要的,因为 FCM 提供 VoIP 通知,这些通知在 Testflight 上没有收到,这非常令人痛苦
问题和解决方案?
我发现了 2 个问题(here & here),似乎都表明这是一个 APNS 证书问题(APNS -> Firebase)。我已重新创建证书并将其添加到 Firebase 控制台(对所有证书生成操作使用相同的 .csr 文件)
设置/配置:
-
APNS 生成密钥并添加到 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)
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;
}
颤动 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(6s 和 8)上完成的。在使用(调试和发布)模式直接从 Mac(Android Studio 和 XCode)构建时,两者都可以与 Firebase FCM 一起使用。从 TestFlight 下载相同的文件时两者都不起作用。
如果有任何可以提供关于错误配置、设置错误或缺少/不正确的 Swift 代码,或者仅仅是错误或遗漏的见解,我们将不胜感激。
【问题讨论】:
-
你确定你正在做一个实际的发布版本吗?发布构建和存档(必然)不是一回事,具体取决于您构建构建的方式。调试不使用与发布相同的证书。调试使用 APNS_SANDBOX 而不是 APNS。甚至可能是您的服务器或 Firebase 上的错误配置。
-
说实话我不知道flutter。我只知道推送通知。我不知道颤振对构建方案或配置有什么影响
-
但是您需要为 PN 做的大部分事情都在 FB 和服务器上。 iOS 只是整个 PN 难题的一小部分。它在 iOS 上实际上比在你的 BE 或 FB 上要简单。 FB 必须配置正确的证书(或最近的 api 密钥),并且 Be 必须将 pn 请求发送到正确的 FB 应用程序才能正常工作。
-
让安卓远离画面。 PN 在 android 上的工作方式与 iOS 不同。在 iOS 中,您需要特定的证书来进行调试和发布以及您可能拥有的任何其他构建配置。让 PN 在本地工作并不意味着 firebase 设置正确。您需要在 apple developer 和 firebase 上完成设置,并确保所有内容都与您发送到 TF 的构建相匹配。
-
我说的是推送通知证书。它们不是由 Xcode 管理的。还有最近的 api 密钥。您可能正在使用它们。 Fb 必须配置为将 PN 发送到正确的证书/api 密钥和 APNS。还要确保您的应用程序要求正确访问 PN。如果您的应用程序没有要求用户允许推送通知,则问题出在 iOS 上。通常这是在启动时完成,但也可以在任何时间完成,例如登录。
标签: ios swift firebase firebase-cloud-messaging apple-push-notifications