簡體   English   中英

Swizzling、模擬器和遠程推送通知 - iOS 14

[英]Swizzling, Simulator, and Remote Push Notifications - iOS 14

關於 iOS 和Firebase Cloud Messaging (FCM)上的遠程通知,我在 iOS 14 中遇到了奇怪的行為。

設備

首先,我無法從 FCM 控制台向我的設備發送測試通知。 我逐字閱讀了文檔,以及一些很好的教程。 這是我的AppDelegate

import SwiftUI
import Firebase

class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        
        FirebaseApp.configure()
        FirebaseConfiguration.shared.setLoggerLevel(.min)
        Messaging.messaging().delegate = self
        
        UNUserNotificationCenter.current().delegate = self
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
            (granted, error) in
            print("Permission granted: \(granted)")
            // 1. Check if permission granted
            guard granted else {
                print("Permission not granted")
                return
            }
            // 2. Attempt registration for remote notifications on the main thread
            DispatchQueue.main.async {
                UIApplication.shared.registerForRemoteNotifications()
            }
        }
        
        application.registerForRemoteNotifications()
        
        return true
    }
    
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
        
        Messaging.messaging().appDidReceiveMessage(userInfo)
        
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }
        print(userInfo)
    }
    
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                     fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        
        Messaging.messaging().appDidReceiveMessage(userInfo)
        
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }
        print(userInfo)
        
        completionHandler(UIBackgroundFetchResult.newData)
    }
    
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Unable to register for remote notifications: \(error.localizedDescription)")
      }
}

@available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        
        let userInfo = notification.request.content.userInfo
        
        Messaging.messaging().appDidReceiveMessage(userInfo)
        
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }
        print(userInfo)
        
        completionHandler([[.banner, .sound]])
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        
        Messaging.messaging().appDidReceiveMessage(userInfo)

        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }
        print(userInfo)
        
        completionHandler()
    }
}

extension AppDelegate: MessagingDelegate {
    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        print("Firebase registration token: \(fcmToken ?? "")")
        
        let dataDict:[String: String] = ["token": fcmToken ?? ""]
        NotificationCenter.default.post(name: NSNotification.Name(rawValue: "FCMToken"), object: nil, userInfo: dataDict)
        // TODO: If necessary send token to application server.
        // Note: This callback is fired at each app startup and whenever a new token is generated.
    }
    
    func application(application: UIApplication,
                     didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        Messaging.messaging().apnsToken = deviceToken
    }
}

let gcmMessageIDKey = "gcm_Message_ID_Key"

我嘗試過的其他事情:

  1. 在 Info.pList 中禁用方法Info.pList (FirebaseAppDelegateProxyEnabled - Boolean - 0)

  2. 添加Messaging.messaging().appDidReceiveMessage(userInfo)以在 App Delegate 中禁用 swizzling 后更新相應的方法。

  3. 將應用程序發送到后台(我們可以在應用程序運行時在前台進行測試嗎?如果它可以在前台工作,它會在前台工作嗎?)

模擬器

其次,我無法向模擬器發送通知,除非我將aps file從 Finder 拖到所述模擬器。 這個aps file是一個 JSON 文件,可用於在模擬器上測試推送通知。 注意:“alert”鍵在 iOS 14 中已棄用。

{
    "Simulator Target Bundle": "com.Example.app",
    "aps": {
        "sound": "default",
        "badge": 1
    }
}

終端命令實用程序如下所示

xcrun simctl push <device> com.Example example.apns

其中<device>是模擬器設備標識符(如果只打開一個模擬器,您也可以使用“booted”代替設備標識符)並且example.apns是您的文件。 我在Atom中創建了我的apns file

這是我在日志中得到的:

在此處輸入圖像描述

這些是我來自 FCM 控制台的報告:

在此處輸入圖像描述

解決了

我的實現一定是錯誤的。 我逐字逐句地按照在模擬器和設備上運行。 模擬器讀取,作為默認錯誤, remote notifications are not supported in the simulator

出現這種情況有幾個原因:

  1. 從 Pusher 到 Project 的捆綁包 ID 不匹配
  2. 不使用整個標識符,例如11FG89IK4-SHEN-13H4-AJD9-SN39FNS82JR用於模擬器。

當我在真實設備上嘗試時,終端也出現錯誤Invalid device: [identifier] 原因是我在Windows > Devices and Simulator for my iPhone 中使用了設備標識符,而不是通過這種方法從控制台返回的設備令牌:


func application(
  _ application: UIApplication,
  didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
  let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
  let token = tokenParts.joined()
  print("Device Token: \(token)")
}

我還使用了Push Notifications Tester而不是 FCM。 我不知道我做錯了什么。 我確定 Firebase 工具可以正常工作。 合理的東西在我這邊。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM