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

已通过Flutter登录,iOS原生端Firestore写入仍失败求助

问题根源分析

Flutter与Swift中不同的Firebase App实例(哪怕配置文件相同)的Auth认证状态是完全隔离的。你在Swift中看到的auth.currentUser不为nil,只是本地缓存的用户信息,该次级App实例并没有持有有效的认证凭证(如ID Token),导致Firestore请求时权限校验失败——尽管Flutter端的默认App实例已经合法登录。

解决方案

方案1:复用Flutter默认的Firebase App实例(推荐)

Flutter的Firebase插件默认使用无名称的默认FirebaseApp实例,直接在Swift中复用这个实例即可共享Auth状态,无需创建次级App:

修改Swift代码:

// 移除次级App初始化逻辑,直接使用默认实例
guard let app = FirebaseApp.app(), let currentUser = Auth.auth(app: app).currentUser else {
    print("User not logged in")
    return
}

let db = Firestore.firestore(app: app)
// ... 构建docRef并调用setData() ...

方案2:通过MethodChannel同步Flutter的Auth凭证到Swift

如果必须使用次级App实例,需要将Flutter端的有效ID Token传递到Swift,完成次级App的认证:

Flutter端代码(传递ID Token)

import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/services.dart';

class AuthNativeChannel {
  static const _channel = MethodChannel('com.yourapp/auth_sync');

  // 在用户登录成功后调用,或后台任务触发前刷新Token
  static Future<void> syncAuthToken() async {
    final user = FirebaseAuth.instance.currentUser;
    if (user != null) {
      final idToken = await user.getIdToken();
      await _channel.invokeMethod('sync_id_token', {'token': idToken});
    }
  }
}

Swift端代码(接收Token并登录次级App)

import Firebase

class AppDelegate: FlutterAppDelegate {
  override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // 初始化默认App(Flutter用的实例)
    FirebaseApp.configure()
    
    // 初始化次级App
    if FirebaseApp.app(name: "flutter-app") == nil {
        let path = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist")!
        let options = FirebaseOptions(contentsOfFile: path)!
        FirebaseApp.configure(name: "flutter-app", options: options)
    }

    // 设置MethodChannel监听Token同步
    let controller = window?.rootViewController as! FlutterViewController
    let authChannel = FlutterMethodChannel(name: "com.yourapp/auth_sync", binaryMessenger: controller.binaryMessenger)
    
    authChannel.setMethodCallHandler { [weak self] call, result in
      guard call.method == "sync_id_token", 
            let args = call.arguments as? [String: String], 
            let token = args["token"] else {
        result(FlutterMethodNotImplemented)
        return
      }
      
      let app = FirebaseApp.app(name: "flutter-app")!
      let auth = Auth.auth(app: app)
      
      // 用ID Token登录次级App
      auth.signIn(withCustomToken: token) { _, error in
        if let error = error {
          print("Auth sync failed: \(error.localizedDescription)")
          result(FlutterError(code: "AUTH_SYNC_ERROR", message: error.localizedDescription, details: nil))
        } else {
          result(nil)
        }
      }
    }
    
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }

  // 后台写入Firestore的逻辑
  func saveBatteryData() {
    guard let app = FirebaseApp.app(name: "flutter-app"),
          let currentUser = Auth.auth(app: app).currentUser else {
      print("No valid user session")
      return
    }

    let db = Firestore.firestore(app: app)
    let docRef = db.collection("users").document(currentUser.uid)
                   .collection("devices").document(UIDevice.current.identifierForVendor!.uuidString)
    
    docRef.setData([
      "battery_level": UIDevice.current.batteryLevel,
      "updated_at": FieldValue.serverTimestamp()
    ]) { error in
      if let error = error {
        print("Write failed: \(error)")
      } else {
        print("Battery data saved successfully")
      }
    }
  }
}
关键注意事项
  1. ID Token有有效期(默认1小时),需要在后台任务触发前主动刷新并同步到Swift端。
  2. 后台任务中如果遇到认证失败,要触发Flutter端重新同步Token。
  3. 复用默认App实例是最简洁的方案,避免多实例状态不一致的问题。

内容的提问来源于stack exchange,提问作者tomgly

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 14:25:12