Flutter: Hide Credential Keys
- Published on
- Authors

- Name
- Mudassir
- Github
- @Lzyct
In some cases, we need to hide some credential keys on our Application like CLIENT_ID, and CLIENT_SECRET even for your GOOGLE_MAP_API key. In my previous post talking about Flutter: Store data based on Environment, we only hide the key from the Dart Code.
So, in this article. We will be talking about how to hide credential keys in Android and iOS. For example, we will hide our google maps API key which we will use the google_maps_flutter library. You can see the documentation for more detailed implementation.
So let's start! 🚀
Flutter
In the flutter, we need to add our API key to the JSON file
/// .env.json
{
...
"GOOGLE_MAP_API": "thisIssampleAPIKey"
...
}
And then you can call the API key on the Dart code.
String.fromEnvironment("GOOGLE_MAP_API")
Android
On Android, we need to parse every variable from --dart-define and make them available key:value map to use.
// android/app/build.gradle
...
/// parse dart-define
def dartEnvironmentVariables = []
if (project.hasProperty('dart-defines')) {
dartEnvironmentVariables = project.property('dart-defines')
.split(',')
.collectEntries { entry ->
def pair = new String(entry.decodeBase64(), 'UTF-8').split('=')
[(pair.first()): pair.last()]
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
...
With this, we successfully parsed the base64 version of every variable. So, how to use that? We can pass that data to Android resources.
<!--android/app/src/main/res/values/strings.xml -->
<string name="map_key" translatable="false">@string/google_map_api</string>
Don't forget to register the string key first on the build.gradle
// android/app/build.gradle
...
defaultConfig {
// TODO: Specify your unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.app"
minSdkVersion 20
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true
resValue "string", "google_map_api", dartEnvironmentVariables.GOOGLE_MAP_API
...
}
And on AndroidManifest.xml, we can call the Google Map API key with
<!-- android/app/main/AndroidManifest.xml -->
<application
....>
<meta-data android:name="com.google.android.geo.API_KEY"
android:value="@string/map_key"/>
</application>
iOS
On iOS also need to parse the --dart-define so the native iOS can read the variables.
First, we need to add a key on ios/Runner/Info.plist
<plist>
<dict>
...
<key>DART_DEFINES</key>
<string>$(DART_DEFINES)</string>
</dict>
</plist>
And, to access the --dart-define values from Swift code
// ios/Runner/AppDelegate.swift
import UIKit
import Flutter
import GoogleMaps
import flutter_local_notifications
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Extract variable from --dart-define
let dartDefinesString = Bundle.main.infoDictionary!["DART_DEFINES"] as! String
var dartDefinesDictionary = [String:String]()
for definedValue in dartDefinesString.components(separatedBy: ",") {
let decoded = String(data: Data(base64Encoded: definedValue)!, encoding: .utf8)!
let values = decoded.components(separatedBy: "=")
dartDefinesDictionary[values[0]] = values[1]
}
GMSServices.provideAPIKey(dartDefinesDictionary["GOOGLE_MAP_API"]!)
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as UNUserNotificationCenterDelegate
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
That's it! Now we can use your Google Map API key inside our native code without worrying that our keys are exposed in our native code.
Reference: How to setup dart-define for keys and secrets on Android and iOS in Flutter apps