Swizzling, симулятор и удаленные push-уведомления — iOS 14

Я получаю странное поведение в iOS 14 в отношении удаленных уведомлений на iOS и Firebase Cloud Messaging (FCM).

УСТРОЙСТВО

Во-первых, я не могу отправлять тестовые уведомления на свое устройство из консоли 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. Отключение метода swizzling в Info.pList (FirebaseAppDelegateProxyEnabled - Boolean - 0)

  2. Добавление Messaging.messaging().appDidReceiveMessage(userInfo) для обновления соответствующих методов после отключения swizzling в App Delegate.

  3. Отправка приложения в фоновый режим (можно ли протестировать его на переднем плане во время работы приложения? Будет ли оно работать на переднем плане, если оно вообще работает?)

СИМУЛЯТОР

Во-вторых, я не могу отправлять уведомления в симулятор, пока не перетащу aps file из Finder в указанный симулятор. Этот aps file представляет собой файл JSON, который я могу использовать для тестирования push-уведомлений на симуляторах. Примечание. Клавиша оповещения устарела в 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 — ваш файл. Я создал свой apns file в Atom.

Вот что я получаю в журналах:

введите здесь описание изображения

Это мои отчеты из консоли FCM:

введите здесь описание изображения




Ответы (1)


РЕШЕНО

Моя реализация, должно быть, была неправильной. Я следовал этому дословно и заработал на симуляторе и устройстве. . Симулятор прочитал ошибку по умолчанию remote notifications are not supported in the simulator.

Есть несколько причин, почему это может быть так:

  1. Идентификаторы пакетов от Pusher до Project не совпадают
  2. Не использовать весь идентификатор, например. 11FG89IK4-SHEN-13H4-AJD9-SN39FNS82JR для симулятора.

У меня также была ошибка в терминале Invalid device: [identifier], когда я пробовал на реальном устройстве. Причина в том, что я использовал идентификатор устройства в Windows > Devices and Simulator для своего 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-уведомлений вместо FCM. Я не знаю, что я делал не так. Я уверен, что инструмент Firebase работает нормально. Разумно что-то с моей стороны.

person David    schedule 27.11.2020
comment
Отмечая также, что это не решение с точки зрения Firebase! Я до сих пор не знаю, что я сделал не так. Более того, я получил то, что мне нужно для работы. Принял бы более точный ответ или лучше решил! - person David; 27.11.2020