iosswiftfirebase-cloud-messagingapple-push-notifications

AppDelegate Firebase Push Notification problem after migrating to Swift 6


This is my AppDeligate:

import Firebase
import FirebaseCore
import FirebaseMessaging
import UserNotifications
import SwiftUI


class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    
    @AppStorage("whatWas") var whatWas: String = ""
    
    let gcmMessageIDKey = "gcm.message_id"
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        
        FirebaseApp.configure()
        UNUserNotificationCenter.current().delegate = self
        
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
        }
        
        application.registerForRemoteNotifications()
        Messaging.messaging().delegate = self

        return true
    }

    
    // Receive displayed notifications for iOS 10 devices.
    nonisolated func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
    ) {
        completionHandler([.banner, .badge])
    }

    nonisolated func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
      
        // THIS ONE IS ONLY CALLED WHEN YOU TAP ON RECEIVED MESSAGE
        let userInfo = response.notification.request.content.userInfo
        
        let notifType = userInfo["notifType"] as? String
        
        if(notifType == "comment" || notifType == "reply"){
            let meme = userInfo["meme"] as? String
            let memeid = userInfo["memeID"] as? String
            let size = userInfo["size"] as? String
            let title = userInfo["memeTitle"] as? String
            
            var fin = meme! + "||" + memeid! + "||" + size!
            
            if(title! != ""){
                fin += "||" + title!
            }else{
                fin += "||null"
            }
            
            Task { @MainActor in
                whatWas = fin
            }
        }
        
        completionHandler()
    }
    
    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Unable to register for remote notifications: \(error.localizedDescription)")
    }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        Messaging.messaging().apnsToken = deviceToken
    }
}



extension AppDelegate: MessagingDelegate {
    
  // [START refresh_token]
    nonisolated func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
        print("Firebase registration token: \(String(describing: fcmToken))")
        
        @AppStorage("notifToken") var notifToken: String = ""
        
        if(fcmToken != nil){
            
            let noto = String(fcmToken!)
            
            if(notifToken != noto){
                notifToken = noto
            }

            Task {
                await Functions.lastOnline()
            }
        }

        let dataDict: [String: String] = ["token": fcmToken ?? ""]
        NotificationCenter.default.post(
            name: Notification.Name("FCMToken"),
            object: nil,
            userInfo: dataDict
        )
    }
}

After migrating to Swift 6, the app crashes while starting.

It only works when I comment out those lines:

//        UNUserNotificationCenter.current().delegate = self
//        
//        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
//        }

but I don't know what to do now.


Solution

  • There is a thread on Apple Developer Forum regarding this issue.
    The proposed solution is to use the Swift async function variant of the API.

    let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
    
    Task {
        do {
            _ = try await UNUserNotificationCenter.current().requestAuthorization(options: authOptions)
        } catch {
            // ...
        }
    }