You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 21:45:13