Updated 28 April 2023
Instead of hard coding, Google maps API key in AndroidManifest.xml and AppDelegate.swift. We can change the Google Maps key dynamically anytime.
We can store the Google Maps key on the server and can get using the rest API. Map key can change the key at runtime after getting from the server.
Check out more about our Flutter app development.
We have to add a key at run time in native code AndroidManifest.xml and AppDelegate.swift. Flutter provides a way to communicate with native code through the Flutter platform channel.
Let’s check implementation at Fluter’s Dart code end.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; void main() { runApp(MaterialApp( title: 'Flutter Google Maps API Key', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage(), )); } class MyHomePage extends StatefulWidget { @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { ///Declare your flutter channel static const METHOD_CHANNEL = const MethodChannel('com.map_api_key.flutter'); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Flutter Google Maps API Key'), ), body: Center( child: Text( 'You have to call Rest API to get the Google Maps API key from the server.', ), ), ); } @override initState() { super.initState(); ///Pass your Google maps API key which has received from the server. _setGoogleMapApiKey("Your Google Maps API key"); } Future<void> _setGoogleMapApiKey(String mapKey) async { /// Map data for passing to native code Map<String, dynamic> requestData = {"mapKey": mapKey}; METHOD_CHANNEL.invokeMethod('setGoogleMapKey', requestData).then((value) { /// You can receive result back from native code }); } } |
Let’s check implementation at Native Android end.
We have to add meta data in AndroidManifest.xml.
1 2 3 |
<meta-data android:name="com.google.android.geo.API_KEY" android:value= ""/> |
Receive Google Maps API key from Flutter Channel.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
import android.content.pm.PackageManager import android.util.Log import androidx.annotation.NonNull import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel class MainActivity : FlutterActivity() { private val CHANNEL = "com.map_api_key.flutter" // Unique Channel override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel( flutterEngine.dartExecutor.binaryMessenger, CHANNEL ).setMethodCallHandler { call, result -> if (call.method == "setGoogleMapKey") { val mapKey = call.argument<String>("mapKey") mapKey?.let { setMapKey(it) } } else { result.notImplemented() } } } private fun setMapKey(mapKey: String) { Log.d("Tag", "_setMapKey ==>${mapKey}") try { val applicationInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA) applicationInfo.metaData.putString("com.google.android.geo.API_KEY", mapKey) } catch (e: PackageManager.NameNotFoundException) { e.printStackTrace() } } } |
Let’s check implementation at Native IOS end.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
import UIKit import Flutter import GoogleMaps @UIApplicationMain @objc class AppDelegate: FlutterAppDelegate { override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) let controller : FlutterViewController = window?.rootViewController as! FlutterViewController let flutterChannel = FlutterMethodChannel(name: "plugins.flutter.io/firebase_messaging_background", binaryMessenger: controller.binaryMessenger) flutterChannel.setMethodCallHandler({ (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in if call.method == "setGoogleMapKey" { if let jsonResult = call.arguments as? Dictionary<String, AnyObject> { let googleMapsApiKey = jsonResult["mapKey"] as? String ?? "" GMSServices.provideAPIKey(googleMapsApiKey) } } else { result(FlutterMethodNotImplemented) return } }) return super.application(application, didFinishLaunchingWithOptions: launchOptions) } } |
I hope this blog will help to set Google Map API key dynamically.
Happy Learning 🙂
Reference Links:
https://mobikul.com/flutter-platform-channel/
https://flutter.dev/docs/development/platform-integration/platform-channels
If you have more details or questions, you can reply to the received confirmation email.
Back to Home
– Please add the file / location of where to add the native code for Android and iOS (useful for people who do not know the Android / iOS structure):
Android: ‘MainActivity.kt’ located in ‘/android/app/src/main/kotlin/’
iOS: ‘AppDelegate.swift’ lcoated in ‘/ios/Runner/’
– There is a big fault in the iOS code. The FlutterMethodChannel’s name is set to “plugins.flutter.io/firebase_messaging_background”. This should be “com.map_api_key.flutter”.
Not the best tutorial, not even tested (see last point). But unfortunately the only one that explains both platforms.