🔥
FlutterでGoogleマップのapiキーをenv化してWeb, Android, iOSに対応させる。
env化しようと思ったが意外と情報がなかったのでメモ。
env化するメリット
- githubなどにあげた時にapiキーがあがらないので不正使用されにくい。
- 環境に合わせてキーを使い分けできる。
- 他の人がgithubなどからcloneして使う時、一ファイルだけapiキーを書き足せばいいので簡単。
env化のデメリット
- Flutter&Google Mapだと1プラットフォームずつ設定しなければならいのでちょっと面倒くさい。
やってみる
env.json作成
プロジェクトのルートディレクトリにenv.jsonを作る。リリース用とデバック用のキーを分けたかったら、env/release-env.jsonとenv/debug-env.jsonを作る。
env.json登録
IntelIJ(Android Studio)のConfigurationをいじる
-
上のmain.dartと書いてあるところを押す。
上のmain.dartと書いてあるところを押す。 -
Edit Configurations...
を押す。 -
図の通り変更する。
VSCodeなど使っている人
実行時に以下のコマンドを入力する。
flutter run --dart-define-from-file=env.json
envの中身を書く
APIキー追加
env.json
{
"GMAP_ANDROID_KEY": "(Android用キー)",
"GMAP_IOS_KEY": "(iOS用キー)",
"GMAP_WEB_KEY": "(Web用キー)"
}
gitignore
.gitignore
env/*
env.json
!ex-*.json # サンプル用の空欄のex-env.jsonなどはignoreしない。
組み込み
dartからはどうやって読める?
String gmapWebKey = String.fromEnvironment("GMAP_WEB_KEY")
これで取得できます。
Android実装
android/app/build.gradle
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
flutterVersionCode = '1'
}
def flutterVersionName = localProperties.getProperty('flutter.versionName')
if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
+ def dartDefines= []
+ if (project.hasProperty('dart-defines')) {
+ dartDefines = project.property('dart-defines').split(',').collectEntries{ entry ->
+ def pair = new String(entry.decodeBase64(), 'UTF-8').split('=')
+ [(pair.first()): pair.last()]
+ }
+ }
android/app/build.gradle
android {
// (省略)
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.amegamo.last_two_hours"
// You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
minSdkVersion 24
targetSdkVersion 34
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
+ resValue "string", "GMAP_KEY", "${dartDefines.GMAP_ANDROID_KEY}"
}
android/app/src/main/AndroidManifest.xml
<application
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:enableOnBackInvokedCallback="true"
android:usesCleartextTraffic="true">
- <meta-data
- android:name="com.google.android.geo.API_KEY"
- android:value="(キー)" />
+ <meta-data
+ android:name="com.google.android.geo.API_KEY"
+ android:value="@string/GMAP_KEY" />
iOS実装
ios/Runner/Info.plist
+ <key>DartDefines</key>
+ <string>$(DART_DEFINES)</string>
</dict>
</plist>
ios/Runner/AppDelegate.swift
- GMSServices.provideAPIKey("(キー)")
+ let dartDefinesString = Bundle.main.infoDictionary!["DartDefines"] as! String
+ var dartDefines = [String:String]()
+ for definedValue in dartDefinesString.components(separatedBy: ",") {
+ let decoded = String(data: Data(base64Encoded: definedValue)!, encoding: .utf8)!
+ let values = decoded.components(separatedBy: "=")
+ dartDefines[values[0]] = values[1]
+ }
+ GMSServices.provideAPIKey(dartDefines["GMAP_IOS_KEY"]!)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Web実装
dart公式のjsパッケージ使用。(標準のdart:jsよりpackage:jsの方がwasm対応)
pubspec.yaml
+ js: ^0.6.7
web/index.html
<body>
+<script>
+ function setGmapApiKey(key) {
+ const sc=document.createElement("script");
+ sc.src=`https://maps.googleapis.com/maps/api/js?key=${key}&v=quarterly`;
+ document.head.appendChild(sc);
+ }
+</script>
cuiでやってもguiでやってもいい。
touch lib/js_or_empty.dart
touch lib/web_import.except.dart
js_or_empty.dart
export 'web_import_except.dart' if (dart.library.js) 'package:js/js.dart';
web_import_except.dart
class JS {
final String? name;
const JS([this.name]);
}
そして、main.dart
でapiキーをセットする。
main.dart
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
+import 'js_or_empty.dart';
+("setGmapApiKey")
+external void _setGmapApiKey(String key);
void main() {
+ if (kIsWeb) {
+ const gmapWebKey = String.fromEnvironment("GMAP_WEB_KEY");
+ _setGmapApiKey(gmapWebKey);
+ }
runApp(
const MaterialApp(
home: Scaffold(
body: GoogleMap(
initialCameraPosition: CameraPosition(
target: LatLng(35.6680456583835, 139.6953623525739),
),
),
),
),
);
}
}
完成!
完成!イェーイ!
Discussion
ご指摘ありがとうございます。
env.json
の間違いでしたので、訂正させていただきます。ちなみに、 によれば、GithubのPull Requestを使ってくれと書いてありますね。時間が空いた時にGithub連携もしようと思います。