swiftflutterfirebasegoogle-cloud-firestorefirebase-authentication

Firestore write fails in iOS native despite valid Flutter login


I'm building a Flutter app that uses Firebase Auth and Firestore. Everything works fine on the Flutter side.

Now, I need to save battery info from iOS native Swift code (in AppDelegate.swift) so it can run in the background — which Flutter doesn't support directly.

To do this, I'm using a secondary FirebaseApp instance in Swift (named "flutter-app"), and I'm trying to write to Firestore using the existing user who was already authenticated in Flutter.

However, when I try to write to Firestore from Swift, I get this error:

[FirebaseFirestore][I-FST000001] WriteStream (313536646433373138) Stream error: 'Permission denied: Missing or insufficient permissions.'
[FirebaseFirestore][I-FST000001] Write at users/{uid}/devices/{deviceId} failed: Missing or insufficient permissions.

Even though:

Here’s the relevant Swift code:

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)
}

let app = FirebaseApp.app(name: "flutter-app")!
let db = Firestore.firestore(app: app)
let auth = Auth.auth(app: app)

guard let currentUser = auth.currentUser else {
    print("User not logged in")
    return
}

// ... build docRef and call setData() ...

Here are the Firestore rules:

rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {
    match /users/{userId} {
      allow read, write, update: if request.auth != null && request.auth.uid == userId;

      match /devices/{deviceId} {
        allow read, write, update: if request.auth != null && request.auth.uid == userId;
      }
    }
  }
}

If there's anything I'm missing about how authentication works across native/Flutter with secondary FirebaseApp, I’d really appreciate any help or suggestions!


Solution

  • The issue was caused by Firebase dose not use the same instance in both flutter and swift, and Firestore being accessed from Swift before Flutter had finished initializing it.

    Since Firestore locks its settings at first access, calling Firestore.firestore() too early in Swift (before Flutter finishes initialization) caused a fatal crash.

    To fix it, I made sure Flutter fully initialized Firebase and triggered a dummy Firestore call before any Swift code touched Firestore. In main.dart, I added:

    await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
    await FirebaseFirestore.instance.collection("initcheck").limit(1).get();
    

    Since my Firestore rules required authentication, I also added:

    match /initcheck/{docId} {
      allow read: if request.auth != null;
    }
    

    After that, saving data from Swift using the logged-in user worked perfectly.