【问题标题】:SwiftUI 2 Firebase push notificationSwiftUI 2 Firebase 推送通知
【发布时间】:2021-02-06 21:19:30
【问题描述】:

所以,我正在使用 SwiftUI 2 和新的应用程序生命周期构建 iOS 应用程序,尝试实现 AppsDelegate 和 Firebase 推送通知

这里是我的代码示例

import SwiftUI

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

和 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()
    }
    
}

但是当我测试来自 firebase 控制台的通知时,它没有出现。

【问题讨论】:

  • 你是在设备上测试还是在模拟器上测试?由于模拟器无法接收通知。
  • 可以在设备上测试,但您也可以在模拟器上测试推送通知
  • 您只能在模拟器上测试 APNS 通知。不是来自 Firebase 的通知。此外,如果您正在为至少需要 iOS14 的 SwiftUI 构建,为什么您的代码要进行可用性检查以确保操作系统至少是 iOS10?看起来你那里有一些冗余代码。
  • AppDelegate 来自我刚刚复制的 Firebase 示例项目,请注意这种方法适用于 UIKit 项目。只是我不知道 Firebase Cloud 消息在新应用程序生命周期中是如何工作的?

标签: swift firebase push-notification swiftui


【解决方案1】:

我能够让您的代码正常工作。我认为 Firebase 在调整 AppDelegate 时存在问题。

如果您通过将密钥 FirebaseAppDelegateProxyEnabled 添加到您的 Info.plist 来禁用 swizzling,将其设为 Boolean 并将其设置为 NO

然后在您的AppDelegate 中,您需要添加以下内容,以便它向 Firebase 注册 APNS 令牌。:

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

要让 Firebase 云消息传递工作,它需要在 APNS 令牌与其令牌之间建立链接。如果没有链接,您将无法发送消息。

请注意,通过禁用 swizzling,某些属性会 您必须手动更新。

您应该仔细阅读documentation。在撰写此答案时,如果您禁用 swizzling,则需要更新 几个地方

AppDelegate 中有三个。第一个如上图,另外两个在这里,是用来接收后台消息的。

您正在向委托方法添加以下行:

Messaging.messaging().appDidReceiveMessage(userInfo)
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
  // If you are receiving a notification message while your app is in the background,
  // this callback will not be fired till the user taps on the notification launching the application.
  // TODO: Handle data of notification

  // With swizzling disabled you must let Messaging know about the message, for Analytics
  Messaging.messaging().appDidReceiveMessage(userInfo) // <- this line needs to be uncommented

  // Print message ID.
  if let messageID = userInfo[gcmMessageIDKey] {
    print("Message ID: \(messageID)")
  }

  // Print full message.
  print(userInfo)
}

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                 fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
  // If you are receiving a notification message while your app is in the background,
  // this callback will not be fired till the user taps on the notification launching the application.
  // TODO: Handle data of notification

  // With swizzling disabled you must let Messaging know about the message, for Analytics
  Messaging.messaging().appDidReceiveMessage(userInfo) // <- this line needs to be uncommented

  // Print message ID.
  if let messageID = userInfo[gcmMessageIDKey] {
    print("Message ID: \(messageID)")
  }

  // Print full message.
  print(userInfo)

  completionHandler(UIBackgroundFetchResult.newData)
}

UNUserNotificationCenterDelegate 中有两个。在委托方法中添加以下行

Messaging.messaging().appDidReceiveMessage(userInfo)
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) // <- this line needs to be uncommented

    // Print message ID.
    if let messageID = userInfo[gcmMessageIDKey] {
      print("Message ID: \(messageID)")
    }

    // Print full message.
    print(userInfo)

    // Change this to your preferred presentation option
    completionHandler([[.alert, .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)")
    }

    // With swizzling disabled you must let Messaging know about the message, for Analytics
    Messaging.messaging().appDidReceiveMessage(userInfo) // <- this line needs to be uncommented

    // Print full message.
    print(userInfo)

    completionHandler()
  }
}

以上代码摘自 Firebase 的云消息传递文档。他们在代码的 cmets 中非常清楚如果您禁用了 swizzling 需要做什么。

根据您的项目中可能包含的其他 Firebase 模块,您可能需要手动更新其他值。这是您需要仔细检查文档和代码示例的地方,以了解您必须进行哪些更改。

【讨论】:

  • 感谢@Andrew,这行得通!你可以说Note that by disabling swizzling there will be certain properties that you will have to update manually.你的意思更详细吗?
  • 再次感谢您提供的详细信息,非常感谢。
猜你喜欢
  • 1970-01-01
  • 2017-03-05
  • 2018-09-19
  • 1970-01-01
  • 1970-01-01
  • 2019-03-18
  • 1970-01-01
  • 1970-01-01
  • 2018-12-17
相关资源
最近更新 更多