Hattori Hanzō
Hattori Hanzō

Reputation: 2483

SwiftUI 2 Firebase push notification

So, I am building iOS app with SwiftUI 2 and new Application life cycle, trying to implement AppsDelegate and Firebase push notification

here my codes sample

import SwiftUI

@main
struct App: App {
    
    @UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
    
    var body: some Scene {
        WindowGroup {
            ContentView().environmentObject(AppSettings())
        }
    }
}

and AppDelegate

import Firebase
import FirebaseMessaging
import UserNotifications
import Foundation
import UIKit
class AppDelegate: NSObject {
    
    let gcmMessageIDKey = "gcm.message_id"
    
    private func setupFirebase(application: UIApplication) {
        FirebaseApp.configure()

        if #available(iOS 10.0, *) {
            // For iOS 10 display notification (sent via APNS)
            UNUserNotificationCenter.current().delegate = self

            let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
            UNUserNotificationCenter.current().requestAuthorization(
                options: authOptions,
                completionHandler: {_, _ in })
        } else {
            let settings: UIUserNotificationSettings = UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
            application.registerUserNotificationSettings(settings)
        }
        Messaging.messaging().delegate = self
        application.registerForRemoteNotifications()
    }
    
}

extension AppDelegate: UIApplicationDelegate {
    
    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
        setupFirebase(application: application)
        return true
    }
    
}

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

@available(iOS 10, *)
extension AppDelegate: UNUserNotificationCenterDelegate {
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        let userInfo = notification.request.content.userInfo
        
        // With swizzling disabled you must let Messaging know about the message, for Analytics
        // Messaging.messaging().appDidReceiveMessage(userInfo)
        
        // Print message ID.
        
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }
        
        // Print full message.
        // print(userInfo)
        
        completionHandler([.banner, .badge, .sound])
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        // Print message ID.
        
        if let messageID = userInfo[gcmMessageIDKey] {
            print("Message ID: \(messageID)")
        }
        
        // Print full message.
        print(userInfo)
        
        completionHandler()
    }
    
}

but when I’m testing notifications from firebase console, it's not coming.

Upvotes: 8

Views: 5153

Answers (1)

Andrew
Andrew

Reputation: 28539

Update Dec 2022


When this answer was written Firebase allowed you to disable swizzling, but there were several additional areas that had to be updated to make it work.

Firebase have now removed these additional requirements, and you should update your implementation accordingly.

SwiftUI apps should use the UIApplicationDelegateAdaptor or NSApplicationDelegateAdaptor property wrappers to provide a type corresponding to the appropriate app delegate protocol.

You should check the documentation careful as posts on SO can easily become out of date.

Implementation


I was able to get your code to work. I think that Firebase has an issue with swizzling the AppDelegate.

If you disable swizzling by adding the key FirebaseAppDelegateProxyEnabled to your Info.plist, making it a Boolean and setting it to NO.

Then in your AppDelegate you need to add the following, so that it registers the APNS token with Firebase.:

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

For Firebase Cloud Messaging to work it needs to make a link between the APNS token and its token. If no link is made then you will not be able to send messages.

You may also want to set a Messaging delegate, this allows you to monitor for token refresh. That can be done by conforming to the messaging delegate protocol, more information can be found here.

Upvotes: 8

Related Questions