SwiftUI项目中如何从App Delegate提取FCM令牌数据并存入Firestore
解决方案
1. 用ObservableObject实现跨层数据传递
SwiftUI和UIKit上下文不同,我们可以用ObservableObject作为中间桥梁,传递FCM令牌并处理存储逻辑:
import FirebaseFirestoreSwift import FirebaseMessaging import FirebaseAuth import Foundation class TokenManager: ObservableObject { @Published var fcmToken: String? // 将令牌存入Firestore的方法 func saveTokenToFirestore() { guard let token = fcmToken, let currentUser = Auth.auth().currentUser, let userID = currentUser.uid else { // 未登录或令牌为空,不执行存储 return } let tokenModel = FCMToken( userID: userID, token: token, createdAt: Date() ) do { // 用userID作为文档ID,避免同一用户重复存储令牌 try Firestore.firestore().collection("fcmTokens").document(userID).setData(from: tokenModel) } catch { print("存储FCM令牌失败: \(error.localizedDescription)") } } }
2. 在App入口注入TokenManager
在你的App结构体中,把TokenManager注入环境变量,让UIKit的AppDelegate和SwiftUI视图都能访问:
@main struct YourApp: App { @StateObject private var tokenManager = TokenManager() @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate var body: some Scene { WindowGroup { HomeView() .environmentObject(tokenManager) } } // 初始化时给AppDelegate传递TokenManager实例 init() { appDelegate.tokenManager = tokenManager } }
3. 修改AppDelegate接收并传递令牌
更新AppDelegate,添加TokenManager属性,在MessagingDelegate方法中更新令牌:
import UIKit import FirebaseMessaging class AppDelegate: UIResponder, UIApplicationDelegate { var tokenManager: TokenManager? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { FirebaseApp.configure() Messaging.messaging().delegate = self return true } } extension AppDelegate: MessagingDelegate { func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) { guard let token = fcmToken else { return } // 更新TokenManager中的令牌 tokenManager?.fcmToken = token // 可直接尝试存储(若用户已登录),也可交给SwiftUI视图处理 tokenManager?.saveTokenToFirestore() } }
4. 在HomeView中处理登录后的存储逻辑
如果需要在用户登录完成后触发存储,可在HomeView中监听登录状态和令牌变化:
import SwiftUI import FirebaseAuth struct HomeView: View { @EnvironmentObject private var tokenManager: TokenManager @State private var user: User? var body: some View { Text("首页") .onAppear { // 监听用户登录状态变更 Auth.auth().addStateDidChangeListener { auth, user in self.user = user // 用户登录且令牌存在时执行存储 if user != nil, tokenManager.fcmToken != nil { tokenManager.saveTokenToFirestore() } } } } }
5. 优化FCMToken模型
去掉@DocumentID的默认UUID,因为我们用userID作为文档ID:
struct FCMToken: Codable, Identifiable { @DocumentID var id: String? // 自动映射Firestore文档ID(即userID) var userID: String? var token: String var createdAt: Date enum CodingKeys: String, CodingKey { case userID case token case createdAt } }
关键说明
ObservableObject让SwiftUI视图自动响应令牌变化,无需手动传递数据。- 用userID作为文档ID,同一用户的令牌会自动覆盖,避免冗余数据。
- 存储逻辑既可以在
MessagingDelegate中直接触发,也可以在SwiftUI视图监听登录状态后执行,根据业务需求选择即可。
内容的提问来源于stack exchange,提问作者Apekshik Panigrahi
相关产品推荐
相关产品推荐

