Skip to content

Firebase Remote Config - Support multiple Firebase apps with individual namespaces #12876

Open
@asetiyadi-MLB

Description

@asetiyadi-MLB

Description

We have an iOS app that allows users to pick target environment at runtime. Each environment has the each own plist file, ie GoogleService-Info-Staging.plist or GoogleService-Info-Prod.plist.

Whenever user switch environment, I teardown the FIrebase

private(set) var remoteConfig: RemoteConfig?

public func tearDownFirebase() async {
    if let app = FirebaseApp.app() {
      Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(false)
      remoteConfig = nil
      await app.delete()
    }
  }

Then reinitiate the Firebase and RemoteConfig

public init(plist: Plist) {
    if FirebaseApp.app() == nil {
      guard let plistPath = Bundle.module.path(forResource: plist, ofType: "plist"),
        let firebaseOptions = FirebaseOptions(contentsOfFile: plistPath)
      else {
        BP.Log.log(Events.firebaseStartedWithoutOptions(env: plist))
        FirebaseApp.configure()
        return
      }

      FirebaseApp.configure(options: firebaseOptions)
    }

    remoteConfig = RemoteConfig.remoteConfig()
  }

  public func startRemoteConfig(environment: EnvironmentName) async throws
    -> RemoteConfigFetchStatus
  {
    guard let remoteConfig else { throw BPFirebaseError.remoteConfigInstance }

    remoteConfig.setDefaults(RemoteConfigKey.defaults as? [String: NSObject])
    remoteConfig.configSettings = RemoteConfigSettings()

    let expirationDuration =
      self.isDeveloperMode(environment: environment)
      ? 0
      : RemoteConfigValues.shared.cacheExpiration

    do {
      let result = try await remoteConfig.fetch(withExpirationDuration: expirationDuration)
      try await remoteConfig.activate()

      return result
    } catch {
      throw BPFirebaseError.remoteConfigFetch
    }
  }

I am able to see that the .plist file for the target environment is being properly passed in and invoked. The FirebaseApp.app() also has different address after the environment is switched.
The problem is with the remote config. It always shows the first values being pulled. So for example, if I start with "Staging" env, and then trying to switch to "Production, after the re-initialization process is complete, it keeps showing Staging remote config values.

Questions:
• Did I do the correct steps and procedures to teardown the Firebase?
• Is there specific steps I need to perform to "reset" the previous RemoteConfig.remoteConfig() to make sure it pulls in the correct value when users switch environment?
• Does Remote Config support switching environment at runtime?

Reproducing the issue

• Make sure you have different .plist file for each target environment
• Allow users to switch environments
• When the switch is requested, make sure the proper plist is used to create the FirebaseApp.app()
• Check that remote config pulls in the right values for a specific environment

Firebase SDK Version

10.24.0

Xcode Version

15.3

Installation Method

Swift Package Manager

Firebase Product(s)

Crashlytics, Firestore, Remote Config

Targeted Platforms

iOS

Relevant Log Output

-- INITIAL ENVIRONMENT --
BP.app/BPFirebase_BPFirebase.bundle/GoogleService-Info-NPD.plist
2024-04-30 21:42:45.944081-0600 BP[74735:36948440] [Firebase/Crashlytics] Version 10.24.0
RemoteConfig activated: Optional(<FIRRemoteConfig: 0x600002aff960>) | app: <FIRApp: 0x600000082c70>
RemoteConfig fetched

-- SWITCH TO STAGING ENVIRONMENT --
BP.app/BPFirebase_BPFirebase.bundle/GoogleService-Info-Staging.plist
RemoteConfig activated: Optional(<FIRRemoteConfig: 0x600002aff960>) | app: <FIRApp: 0x60000023a580>
RemoteConfig fetched

If using Swift Package Manager, the project's Package.resolved

Expand Package.resolved snippet
{
  "pins" : [
    {
      "identity" : "abseil-cpp-binary",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/google/abseil-cpp-binary.git",
      "state" : {
        "revision" : "748c7837511d0e6a507737353af268484e1745e2",
        "version" : "1.2024011601.1"
      }
    },
    {
      "identity" : "app-check",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/google/app-check.git",
      "state" : {
        "revision" : "c218c2054299b15ae577e818bbba16084d3eabe6",
        "version" : "10.18.2"
      }
    },
    {
      "identity" : "firebase-ios-sdk",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/firebase/firebase-ios-sdk.git",
      "state" : {
        "revision" : "42eae77a0af79e9c3f41df04a23c76f05cfdda77",
        "version" : "10.24.0"
      }
    },
    {
      "identity" : "googleappmeasurement",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/google/GoogleAppMeasurement.git",
      "state" : {
        "revision" : "51ba746a9d51a4bd0774b68499b0c73ef6e8570d",
        "version" : "10.24.0"
      }
    },
    {
      "identity" : "googledatatransport",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/google/GoogleDataTransport.git",
      "state" : {
        "revision" : "a637d318ae7ae246b02d7305121275bc75ed5565",
        "version" : "9.4.0"
      }
    },
    {
      "identity" : "googleutilities",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/google/GoogleUtilities.git",
      "state" : {
        "revision" : "26c898aed8bed13b8a63057ee26500abbbcb8d55",
        "version" : "7.13.1"
      }
    },
    {
      "identity" : "grpc-binary",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/google/grpc-binary.git",
      "state" : {
        "revision" : "e9fad491d0673bdda7063a0341fb6b47a30c5359",
        "version" : "1.62.2"
      }
    },
    {
      "identity" : "gtm-session-fetcher",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/google/gtm-session-fetcher.git",
      "state" : {
        "revision" : "9534039303015a84837090d20fa21cae6e5eadb6",
        "version" : "3.3.2"
      }
    },
    {
      "identity" : "interop-ios-for-google-sdks",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/google/interop-ios-for-google-sdks.git",
      "state" : {
        "revision" : "2d12673670417654f08f5f90fdd62926dc3a2648",
        "version" : "100.0.0"
      }
    },
    {
      "identity" : "promises",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/google/promises.git",
      "state" : {
        "revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
        "version" : "2.4.0"
      }
    },
    {
      "identity" : "servicecontext",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/ribtiago/ServiceContext.git",
      "state" : {
        "revision" : "f3ebe4fd8374ecdb8e31201d493772dc6eaab7c3",
        "version" : "2.0.1"
      }
    },
    {
      "identity" : "snapkit",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/SnapKit/SnapKit",
      "state" : {
        "revision" : "d458564516e5676af9c70b4f4b2a9178294f1bc6",
        "version" : "5.0.1"
      }
    },
    {
      "identity" : "swift-collections",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/apple/swift-collections.git",
      "state" : {
        "revision" : "94cf62b3ba8d4bed62680a282d4c25f9c63c2efb",
        "version" : "1.1.0"
      }
    },
    {
      "identity" : "swift-package-manager-google-mobile-ads",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/googleads/swift-package-manager-google-mobile-ads.git",
      "state" : {
        "revision" : "5ff977255c2ba5844e7e9da779f1f2a5a00e0028",
        "version" : "11.2.0"
      }
    },
    {
      "identity" : "swift-package-manager-google-user-messaging-platform",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/googleads/swift-package-manager-google-user-messaging-platform.git",
      "state" : {
        "revision" : "cfe8b2ae16b9bc81f4cdf1d1a12a01a452489c32",
        "version" : "2.3.0"
      }
    },
    {
      "identity" : "swift-protobuf",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/apple/swift-protobuf.git",
      "state" : {
        "revision" : "9f0c76544701845ad98716f3f6a774a892152bcb",
        "version" : "1.26.0"
      }
    },
    {
      "identity" : "swiftuibackports",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/shaps80/SwiftUIBackports.git",
      "state" : {
        "revision" : "dfc492b9907d1c9b78f3ef928add759b798c464d",
        "version" : "1.0.9"
      }
    },
    {
      "identity" : "swiftuiextras",
      "kind" : "remoteSourceControl",
      "location" : "https://github.com/ribtiago/SwiftUIExtras.git",
      "state" : {
        "revision" : "b40c865b2756a0c07145e065f078d5a4c591d08f",
        "version" : "1.9.3"
      }
    }
  ],
  "version" : 2
}

If using CocoaPods, the project's Podfile.lock

Expand Podfile.lock snippet
Replace this line with the contents of your Podfile.lock!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions