已通过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") } } } }
关键注意事项
- ID Token有有效期(默认1小时),需要在后台任务触发前主动刷新并同步到Swift端。
- 后台任务中如果遇到认证失败,要触发Flutter端重新同步Token。
- 复用默认App实例是最简洁的方案,避免多实例状态不一致的问题。
内容的提问来源于stack exchange,提问作者tomgly
相关产品推荐
相关产品推荐

