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

Swift开发中如何在Firebase中正确存储uid与FCM令牌

问题原因

当前代码存在三个核心问题,导致UID无法正常写入、存储结构不符合预期:

  • 引用初始化顺序错误:ref的赋值操作放在了写入数据的逻辑之后,且生成存储节点key的逻辑有误,self.ref.childByAutoId().child("Uid").key拿到的不是token节点下的合法子节点路径
  • 存储格式错误:传入setValue的是数组而非键值对字典,未登录状态下Auth.auth().currentUser?.uid为nil,存入数组时会直接导致字段缺失,且每次触发token回调都会生成新的自动ID节点,产生大量重复无效记录
  • 缺少登录后关联逻辑:仅在获取token时执行一次写入操作,用户完成注册/登录后没有触发更新已有token记录的逻辑,自然无法把UID写入之前生成的记录中
修复方案

1. 提前初始化数据库引用

不要在token回调里才初始化ref,在AppDelegate启动或者控制器初始化阶段就完成赋值:

var ref: DatabaseReference! = Database.database().reference().child("token")

2. 修正token接收回调的存储逻辑

不要每次触发回调都新建记录,以token值为匹配依据避免重复存储,未登录时UID字段先存空字符串:

func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
    messaging.token { [weak self] token, error in
        guard let self = self, let token = token, error == nil else { return }
        
        let tokenRecord: [String: Any] = [
            "Token": token,
            "UID": Auth.auth().currentUser?.uid ?? ""
        ]
        
        // 查询是否已存在当前token的记录
        self.ref.queryOrdered(byChild: "Token")
            .queryEqual(toValue: token)
            .observeSingleEvent(of: .value) { snapshot in
                if snapshot.exists(), let existingRecord = snapshot.children.allObjects.first as? DataSnapshot {
                    // 已有记录直接更新,不新建节点
                    self.ref.child(existingRecord.key).updateChildValues(tokenRecord)
                } else {
                    // 无记录时新建节点
                    let newRecord = self.ref.childByAutoId()
                    newRecord.setValue(tokenRecord)
                }
            }
        print("Current FCM Token: \(token)")
    }
}

3. 增加注册/登录成功后的UID绑定逻辑

在处理注册成功、登录成功的回调位置,调用以下方法,把UID关联到当前设备已存的token记录上:

func updateTokenWithCurrentUid() {
    guard let currentUid = Auth.auth().currentUser?.uid else { return }
    Messaging.messaging().token { [weak self] token, error in
        guard let self = self, let token = token, error == nil else { return }
        // 匹配当前设备的token记录
        self.ref.queryOrdered(byChild: "Token")
            .queryEqual(toValue: token)
            .observeSingleEvent(of: .value) { snapshot in
                guard snapshot.exists(), let record = snapshot.children.allObjects.first as? DataSnapshot else { return }
                // 只更新UID字段,不改动原有token值
                self.ref.child(record.key).updateChildValues(["UID": currentUid])
            }
    }
}
最终效果

调整后数据库存储结构完全符合预期,示例如下:

"token": {
    "-N6tIuKBUkFpzhrEdX6f": {
        "Token": "cs00XevXU0WDsT2z-yginY:APA91bED3KwXRC9dXJN0iJECZu2todoD0cAO9mw_3vx3nd7WLIEkA3UkCWU4GMy5zt1iHOkOvN4OGgVZuBq12WC9LJ3o0QZyB88Rn01z7_kLdoh1ul0_opbTE-IrcZ3ylGaYuLovSfHe",
        "UID": "用户登录后自动补写的uid值"
    }
}
  • 用户未登录打开应用时,自动存储token,UID字段暂时为空
  • 用户完成注册/登录后,自动找到对应token记录补写UID,不会生成重复数据
  • FCM token刷新时会自动更新对应记录,不会出现数据不一致问题

内容的提问来源于stack exchange,提问作者Hello-World

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 16:33:41