3

Based on advice, I would like to manage API keys using Firebase Remote Config to avoid hard-coding API keys like google_maps_flutter suggests. It has an AppDelegate.swift like:

import UIKit
import Flutter
import GoogleMaps

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    GMSServices.provideAPIKey("YOUR KEY HERE")
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

How can the above be modified to fetch the API key from Firebase Remote Config and then pass it to GMSServices?

AWhitford
  • 3,708
  • 3
  • 28
  • 38
  • Hmm, does this mean you are willing to wait for remote config to be fetch before you actually register your key? and if it fails fetching you are fine in not having that functionality. if so then remoteConfig has an option called fetch with a callback block – Joshua Feb 25 '20 at 01:02
  • What is the alternative? I'm just trying to avoid hard-coding API keys in source code. I'm seeking best practice advice for production: https://github.com/flutter/flutter/issues/51267 – AWhitford Feb 25 '20 at 07:25

2 Answers2

1

Based on this article, I came up with:

import UIKit
import Firebase
import Flutter
import GoogleMaps
//import os.log

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
    FirebaseApp.configure()
    RemoteConfig.remoteConfig().fetchAndActivate() { status, error in
      let apiKey : String = RemoteConfig.remoteConfig()["Google_Maps_SDK_for_iOS_API_KEY"].stringValue ?? "MISSING";
      // os_log("Google_Maps_SDK_for_iOS_API_KEY = '%@'", apiKey)
      GMSServices.provideAPIKey(apiKey)
    }
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
}

Is there a better way?

AWhitford
  • 3,708
  • 3
  • 28
  • 38
  • Heads up! I discovered that the above code interferes with the **very first launch** of an app that uses `firebase_remote_config`. See https://github.com/FirebaseExtended/flutterfire/issues/2592 for details. – AWhitford May 20 '20 at 18:31
0

I was thinking of making this as a comment, but decided to make it as my answer as it was too long.

I think it's one way of getting keys from remoteConfig, but again failure can happen where fetch config was not retrieved. One way to solve it is by having a force refresh when it fails, but then again you are relying on firebase for those keys and if for some reason (experienced it before firebase was acquired by google) it went down your app then will be unuseable (so as for many apps).

For me, I still put my API keys bundled with the app just to make sure all the important functionality works.

Another option will be having your API Keys bundled and then having a WebService call to check for new keys once the current keys you have has expired/change. That way you have the capability to immediately expire your keys and change it to another one.

Joshua
  • 2,432
  • 1
  • 20
  • 29
  • 2
    The biggest problem seems to be the fact that the API key can only be passed via SWIFT code, not Dart code. If the Dart API was extended, then I can easily move the API key management to the Flutter/Dart app and provide excellent error handling. As a result, I proposed an API enhancement: https://github.com/flutter/flutter/issues/51433 – AWhitford Feb 27 '20 at 15:44