Flutter 使用 — dart-define 設置環境變數,簡單與雙平台溝通
這篇寫於 2023 年。工具和 API 變化很快,部分步驟可能已經不適用。
當我們在開發 Flutter 時,有時候各平台可能有用到一些服務,會需要 API Key 或是 Token,例如 Android 會在 AndroidManifest.xml、iOS 在 AppDelegate.swift 設置,進行一些三方服務的初始化。存取前會將它們從 base64 格式轉換,才能取得正常內容
可能有些服務需要在 APP 啟動時進行初始化,這時候會透過各平台去設置,需要取得 TOKEN、KEY 等等相關的機密資料,能透過 —dart-define 給予
flutter run --dart-define FLAVOR=development, API_KEY=xxxxxxxxxxxxx
Android 存取#
在 android/app/build.gradle 裡,解析 — dart-define 給予得參數。首先進行基本的字串切分,接著從 base64 格式轉換為正常字串,最後透過 Key & Value 紀錄下來
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()]
}
}
為了讓 AndroidManifest.xml 可以存取和使用,需要將變數設置到 defaultConfig 的 manifestPlaceholders,以大家習慣的 Key Value pair 去設置,Key 通常都是全大寫
manifestPlaceholders = [
API_KEY: dartEnvironmentVariables.API_KEY
]
AndroidManifest.xml
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="${API_KEY}" />
為了在 string 資源檔或是程式執行檔存取,需要將變數加到 defaultConfigs 裡
defaultConfig {
...
resValue "string", "api_key", dartEnvironmentVariables.API_KEY
}
strings.xml
<string name="apiKey" translatable="false">@string/api_key</string>
MainActivity.kt
var apiKey = getString(R.string.api_key)
YiiService.start(apiKey)
iOS 存取#
首先要調整 ios/Runner/Info.plist 設定檔,將 DART_DEFINES Key 加入,這樣就能存取 -dart-define 內容
<key>DART_DEFINES</key>
<string>$(DART_DEFINES)</string>
接著在 AppDelegate.swift 裡的 didFinishLaunchingWithOptions() 解析 — dart-define。跟 Android 做的事情差不多,一樣取得原始內容後,進行字串切分和格式轉換,然後以 Key & Value 儲存
let dartDefinesString = Bundle.main.infoDictionary!["DART_DEFINES"] as! String
var dartEnvironmentVariablesDictionary = [String:String]()
for definedValue in dartDefinesString.components(separatedBy: ",") {
let decoded = String(data: Data(base64Encoded: definedValue)!, encoding: .utf8)!
let values = decoded.components(separatedBy: "=")
dartEnvironmentVariablesDictionary[values[0]] = values[1]
}
一開始進行服務的初始化,載入私密資訊,例如:API Key、Token
YiiService.start(withApiKey: dartEnvironmentVariablesDictionary["API_KEY"]!, in:application, withLaunchOptions:launchOptions)
Flutter 3.7#
在 Flutter 3.7 版本後多了一個新的參數 — dart-define-from-file ,能直接傳遞 Json 檔案,包含所有的機密資料,我們就不需要使用很長的指令了,方便許多
// keys.json
{
"FLAVOR": "development",
"API_KEY": "xxxxxxxxxxxxx"
}
flutter run --dart-define-from-file=keys.json
在程式裡讀取初始設置的變數
const flavor = String.fromEnvironment('FLAVOR');
const apiKey = String.fromEnvironment('API_KEY');
Android#
個別針對 Key 讀取資料
def dartEnvironmentVariables = [
FLAVOR: project.hasProperty('FLAVOR')
? FLAVOR
: 'dev',
API_KEY: project.hasProperty('API_KEY')
? API_KEY
: null,
]
iOS#
新增 Default.xcconfig,並給予預設值,在 — dart-define-from-file 讀取不到資料時可以使用
FLAVOR=dev
API_KEY=xxxxxxxxxx
在 Debug.xcconfig 和 Release.xcconfig 匯入Default.xcconfig
Conclusion#
到這裡,你已經成功讓專案不同了,我們可以輕鬆設置第三方服務的 SDK、API,甚至不用怕秘密會裸露出來,只需要在 CI 流程裡將資料注入即可,也記得要處理未取得資料的情況,讓專案維持高品質。
Reference#
- https://medium.com/flutter-community/how-to-setup-dart-define-for-keys-and-secrets-on-android-and-ios-in-flutter-apps-4f28a10c4b6c
- https://www.jianshu.com/p/5b441bf8723d
- https://itnext.io/secure-your-flutter-project-the-right-way-to-set-environment-variables-with-compile-time-variables-67c3163ff9f4
Articles#
- Flutter Meetup #1 聚會有什麼?還有 Flutter 四月大小事!
- 提升開發效率的好物,Mason 讓你輕鬆撰寫自定義模板!
- 教你製作強大的 Rive 動畫,完成一隻 Flutter Dash,在 APP 跟它互動!
- Flutter 如何根據 Flavor 多環境載入對應的 Firebase Config
- Isolates 在 Flutter 3.7 & Dart 2.19 的升級,你該知道一下!
- 讓人驚艷的 Flutter Forward,釋出 Flutter 3.7 和 Dart 2.19
- 學會運用 Flutter Widgetbook,該管好自己和公司的元件庫了!
- 剛進入 Flutter 嗎?適合初學者食用,GetX 是否適合你呢!
- 你知道 Maestro 嗎,兼具人性的自動化測試框架,Flutter 品質就靠它了 — Part 1: 介紹與使用
- 教你為 Riverpod 2.0 撰寫 Flutter 測試 part.1
- 輕鬆了解 Isar NoSQL DB,用它來實作 Flutter 資料庫吧!
- Flutter 輕鬆實作 i18n,使用 easy_localization_generator 就對了
- Flutter CICD 使用 Gitlab Runner 和 App Center 實作 part.1
- 使用 CodeMagic 和 Firebase 實現 Flutter CICD
- 輕鬆完成Flutter開發環境,最新版!
- Easily understand StatefulWidget LifeCycle of Flutter
- “freezed” makes model class strong and easily
- 提高Flutter性能的小技巧!(一)
- What are Async and Isolates in Flutter?
- LoadBalancer is optimization for Isolates in Flutter
About#
- GitHub: chyiiiiiiiiiiii
- Instagram: flutterluvr.yii
- Linkedin: yiichenhi
- Youtube: Yii
- Youtube: 一起饅頭(美食頻道)
- Email: ab20803@gmail.com
Contribution#
如果覺得文章不錯的話可以贊助,讓我有更多動力和熱情分享學習紀錄和生活!請我喝一杯咖啡吧~
希望有幫助到你/妳,歡迎追蹤我,方便瀏覽最新的文章~
本文原刊登於 Medium。