1

Problem

I want my iOS application to connect to my locally running Emulators, and NEVER bypass the emulator to hit my production services. I've configured everything properly according to hours and hours of scouring across Firebase documentation, and even dipping into StackOverflow questions and GitHub PRs.

Currently, I've got Emulators running for Auth, Functions, and Firestore. As far as I'm aware, the hosts and ports are configured properly. My local functions run fine. I can use the UI.

The moment my authentication code runs, it authenticates using my production service, not my locally running emulator suite. It never even acknowledges the emulator suite.

Code Snippets

In my emulator suite's firebase.json, I have the following code:

{
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "functions": {
    "predeploy": [
      "npm --prefix \"$RESOURCE_DIR\" run lint",
      "npm --prefix \"$RESOURCE_DIR\" run build"
    ]
  },
  "emulators": {
    "auth": {
      "host": "0.0.0.0",
      "port": 9099
    },
    "firestore": {
      "host": "0.0.0.0",
      "port": 8080
    },
    "functions": {
      "host": "0.0.0.0",
      "port": 5001
    },
    "ui": {
      "enabled": true
    }
  }
}

When the emulator suite launches, I see the following output:

┌────────────────┬──────────────┬─────────────────────────────────┐
│ Emulator       │ Host:Port    │ View in Emulator UI             │
├────────────────┼──────────────┼─────────────────────────────────┤
│ Authentication │ 0.0.0.0:9099 │ http://localhost:4001/auth      │
├────────────────┼──────────────┼─────────────────────────────────┤
│ Functions      │ 0.0.0.0:5001 │ http://localhost:4001/functions │
├────────────────┼──────────────┼─────────────────────────────────┤
│ Firestore      │ 0.0.0.0:8080 │ http://localhost:4001/firestore │
└────────────────┴──────────────┴─────────────────────────────────┘

In my iOS app, I do the following:

// FirebaseOptions is populated with a GoogleService-Info.plist per environment,
// then passed into this function.
// However, even using FirebaseApp.configure() changes nothing.
private func initialize(options: FirebaseOptions) {
    FirebaseApp.configure(options: options)
    
    // If we aren't running on local emulator, do nothing else.
    guard isRunningLocalEmulator else {
        return
    }
    
    let host = "0.0.0.0"
    
    // Auth
    Auth.auth().useEmulator(withHost: host, port: 9099)

    // Firestore
    let settings = Firestore.firestore().settings
    settings.host = "\(host):8080"
    settings.isPersistenceEnabled = false
    settings.isSSLEnabled = false

    Firestore.firestore().settings = settings
}

Additional Context

  • I'm using multiple GoogleService-Info.plist files per environment. However, I have tested my code using only a single GoogleService-Info.plist just to ensure this wasn't causing an issue. There was no change to my issue.

Links

What I've Tried

  • Using both localhost and 0.0.0.0 as my emulator hosts.
  • Running on different local simulators.
  • Upgrading and downgrading Firebase to various versions, just to check if something broke.
  • Building on both Xcode 12.5.1 and Xcode 13 RC.
  • Running on both iOS 14.9 and iOS 15.0.

Questions

  1. How do I initialize a FirebaseApp such that it could NEVER have any context of my real projects, so that if local emulation fails for any reason, it will return errors instead of using my production services?
  2. There are two ways to initialize Firestore local emulator. I'm currently using the snippet shown here, but there is also the Firestore.firestore().useEmulator(withHost:port:) method, which is used by the Auth service. I can't tell which is more appropriate.
  3. Why is my application bypassing my local emulators to begin with? (Maybe 1 + 2 will answer this, but I'm stumped.)
bdrelling
  • 830
  • 1
  • 10
  • 27
  • Does this answer your question? [Firebase Firestore emulator on physical IOS / Android device](https://stackoverflow.com/questions/66161387/firebase-firestore-emulator-on-physical-ios-android-device) – Mabel A. Sep 27 '21 at 09:02

1 Answers1

2

What project id are you using?

The reason I’m asking is because project id’s starting demo- are reserved for local (emulated) projects. If you use such, your emulation session will never reach for the cloud. If you use anything else, Firebase (for some reason I don’t understand) wants to use a hybrid model.

How do I initialize a FirebaseApp such that it could NEVER have any context of my real projects, so that if local emulation fails for any reason, it will return errors instead of using my production services?

So that’s my answer for Q1.

If you want to know the background, it arises from a Google Cloud Platform (GCP) convention, where no real project is allowed to have this prefix. Firebase (running on top of it) has adopted this convention and the emulator CLI is aware of it.

It is documented on this subpage but not nearly as relevantly as I think it should.

akauppi
  • 17,018
  • 15
  • 95
  • 120
  • This would actually help with question 3 as well. I'm marking this as the preferred answer for that reason, thank you! – bdrelling Oct 30 '21 at 18:28