Уведомления Firebase Cloud Messaging не отображаются на устройстве iOS (передний план и фон) - PullRequest
3 голосов
/ 09 января 2020

Я использую FCM для создания и отправки уведомлений pu sh для моего приложения iOS.

Среда разработки:

  • Xcode 11,3

  • iPhone X работает iOS 13,3

  • Swift 5,2

Версии Pod:

  • Firebase 6.14.0
  • FirebaseMessaging 4.1.10
  • FirebaseInstanceID 4.2.8

Проблема:

Прежде чем столкнуться с проблемой, я настроил свое приложение так, чтобы оно могло получать уведомления, когда приложение находилось как в фоновом, так и на переднем плане. Очень довольный собой, я передал код. После этого момента я не смог получать уведомления на переднем плане или на заднем плане. Независимо от того, используется ли уведомление с панели мониторинга Cloud Messaging или POSTMAN, я получаю успешный ответ, но уведомление так и не появляется.

Сначала я подумал, что, возможно, достиг квоты уведомлений, но теперь через 2 дня факт.

Для устранения неполадок я попытался:

  1. Удалил и переустановил приложение (которое обновляет токен устройства)
  2. Перемещено UIApplication.shared.registerForRemoteNotifications() до FirebaseApp.configure()
  3. Загрузил бесплатный sh GoogleService-Info.plist и заменил существующий
  4. Проверено, что идентификаторы пакета et c все совпадают
  5. Обновлены модули Firebase до последней (FirebaseMessaging был на 4.1.9, если это помогает)
  6. Установить Messaging.messaging().shouldEstablishDirectChannel = true
  7. Удалены и повторно добавлены необходимые возможности
  8. Установить FirebaseAppDelegateProxyEnabled на ДА и НЕТ
  9. Установить shouldEstablishDirectChannel = true
  10. Установить useMessagingDelegateForDirectChannel = true
  11. Переместил некоторые логи c из didFinishLaunchingWithOptions () в applicationDidBecomeActive ()

Код:

Примечание: это неизмененный код, который изначально работал для меня.

AppDelegate.swift

import UIKit
import Firebase
import FBSDKCoreKit
import GoogleMaps
import SwiftLocation
import GooglePlaces
import Crashlytics
import GoogleSignIn
import Armchair
import UserNotifications
import FirebaseMessaging

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    var window: UIWindow?
    var swipeNavigationViewController: SwipeNavigationViewController!

    override init() {
        super.init()

        FirebaseApp.configure()

        Database.database().isPersistenceEnabled = true
        swipeNavigationViewController = SwipeNavigationViewController()
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool  {
        FirebaseConfiguration.shared.setLoggerLevel(.error)
        ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)

        // Google Maps
        GMSServices.provideAPIKey(FireBaseConstants.GoogleAPIKey)
        GMSPlacesClient.provideAPIKey(FireBaseConstants.GoogleAPIKey)
        GeocoderRequest.GoogleOptions(APIKey: FireBaseConstants.GoogleAPIKey)

        let navigationViewController = UINavigationController(rootViewController: swipeNavigationViewController)
        navigationViewController.setNavigationBarHidden(true, animated: false)

        self.window?.rootViewController = navigationViewController
        self.window?.makeKeyAndVisible()

        showAlertIfPointedTowardProductionDatabase()
        setupReviewRequest()

        UIApplication.shared.registerForRemoteNotifications()

        let center = UNUserNotificationCenter.current()
        center.requestAuthorization(options:[.badge, .alert, .sound]) { (granted, error) in
            // If granted comes true you can enabled features based on authorization.
            guard granted else { return }
            DispatchQueue.main.async {
                print("UserID: \(UserManager.sharedManager.currentUser?.userID)")
                let pushManager = PushNotificationManager(userID: "currently_logged_in_user_id")
                pushManager.registerForPushNotifications()
            }
        }

        UNUserNotificationCenter.current().delegate = self

        return true
    }

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        let handledByFB = ApplicationDelegate.shared.application(app, open: url, options: options)

        var handledByGoogle = false
        if !handledByFB {
            handledByGoogle = GIDSignIn.sharedInstance().handle(url)
        }

        let handled = handledByFB || handledByGoogle

        return handled
    }

    private func setupReviewRequest() {
        //Code...
    }

    // This method will be called when app received push notifications in foreground
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.alert, .badge, .sound])
    }
}

PushNotificationManager.swift

import Foundation
import Firebase
import FirebaseFirestore
import FirebaseMessaging
import UIKit
import UserNotifications

class PushNotificationManager: NSObject, MessagingDelegate, UNUserNotificationCenterDelegate {

    let userID: String
    let gcmMessageIDKey = "gcm.message_id"

    init(userID: String) {
        self.userID = userID
        super.init()
    }

    func registerForPushNotifications() {
        let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]

        UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { (_, error) in
            guard error == nil else{
                print(error!.localizedDescription)
                return
            }
        }

        //get application instance ID
        InstanceID.instanceID().instanceID { (result, error) in
            if let error = error {
                print("Error fetching remote instance ID: \(error)")
            } else if let result = result {
                print("Remote instance ID token: \(result.token)")
            }
        }

        UIApplication.shared.registerForRemoteNotifications()
        updateFirestorePushTokenIfNeeded()
    }

    func updateFirestorePushTokenIfNeeded() {
        if let token = Messaging.messaging().fcmToken {
            //            let usersRef = Firestore.firestore().collection("users_table").document(userID)
            //            usersRef.setData(["fcmToken": token], merge: true)
            print("Remote instance ID token: \(token)")
        }
    }

    func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
        print("Firebase registration token: \(fcmToken)")

        let dataDict:[String: String] = ["token": fcmToken]
        NotificationCenter.default.post(name: Notification.Name("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 messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage) {
        print("Received data message: \(remoteMessage.appData)")
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        print(response)
    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }

        print(userInfo)
    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Unable to register for remote notifications: \(error.localizedDescription)")
    }

    func application(_ application: UIApplication,didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let tokenParts = deviceToken.map { //data -> String in
            return String(format: "%02.2hhx", $0)
        }

        Messaging.messaging().apnsToken = deviceToken
        Messaging.messaging().setAPNSToken(deviceToken, type: .unknown)
        UserDefaults.standard.synchronize()
    }
}

Это была установка используя все следующие ссылки (я уверен, что с несколькими другими я тоже забыл):

Ответная информация:

Почтальон:

{
    "multicast_id": 2586780331808083728,
    "success": 1,
    "failure": 0,
    "canonical_ids": 0,
    "results": [
        {
            "message_id": "0:1578532253832479%2b1845e62b1845e6"
        }
    ]
}

Облачные сообщения:

FCM Console

1 Ответ

2 голосов
/ 09 января 2020

Мне удалось решить проблему, переместив

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)

из PushNotificationManager в AppDelegate. Надеюсь, это поможет кому-то еще!

...