本文主要解決在多環境(測試環境,開發環境等),多渠道情況下,如何優雅快速的進行Flutter打包。
Flutter中的配置
定義一個類,用於從環境中獲取自定義的渠道名,這裡指定的key是ANDROID_CHANNEL
,可以根據自己需要定義key。
class EnvConfig{
/// flutter run --dart-define=ANDROID_CHANNEL=flutter
/// 多渠道打包
/// Android Studio可以配置執行Flutter引數 --dart-define=ANDROID_CHANNEL=flutter
static const CHANNEL=String.fromEnvironment('ANDROID_CHANNEL',defaultValue: 'unknown');
}
複製程式碼
也可以從環境中獲取多個,不同型別的內容。
class EnvConfig{
static const CHANNEL=String.fromEnvironment('ANDROID_CHANNEL',defaultValue: 'unknown');
static const VERSION=int.fromEnvironment('ANDROID_VERSION',defaultValue: 1);
}
複製程式碼
此時在命令中執行引數:
flutter build apk --dart-define=ANDROID_CHANNEL=xiaomi
複製程式碼
這樣CHANNEL
的值就是xiaomi
了,也就是所謂的渠道名。如果是多個--dart-define
,中間空格隔開即可。
flutter build apk --dart-define=ANDROID=xiaomi --dart-define=ANDROID_VERSION=2
複製程式碼
這樣就可以根據變數CHANNEL
進行業務邏輯操作,例如友盟統計渠道。
Android Studio 配置
日常開發,不可能經常手刃命令列,配置run
引數。
配置run args
,內容和上面一致。
如果需要配置多個環境,例如開發環境,測試環境,正式環境,也可以通過這種方式來進行,避免手動修改程式碼,出錯。
- 複製已有的配置內容
- 修改配置名稱
name
,例如生產環境:main-prod
- 修改不同環境引數內容
apk包名輸出
在編譯或者打包時,Flutter會將--dart-define
引數傳遞給Android
的APP元件的build.gradle
檔案。因此可以通過下面方式獲取內容。
def dartEnvironmentVariables = [
ANDROID_CHANNEL: 'android',
]
if (project.hasProperty('dart-defines')) {
println('print dart defines proerty')
dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
.split(',')
.collectEntries { entry ->
def pair = new String(entry.decodeBase64(), 'UTF-8').split('=')
println(pair.first()+':'+pair.last())
[(pair.first()): pair.last()]
}
}
複製程式碼
這裡有個注意事項:
從Flutter
傳遞過來的dart-defines
的value
是會進行加密的,所以需要進行解密,而且不同版本的Flutter
加密方式也不一樣。在Flutter 2.2
採用上面程式碼entry.decodeBase64()
。而老版本採用下面程式碼URLDecoder.decode(entry)
。
def dartEnvironmentVariables = [
ANDROID_CHANNEL: 'android',
OTHER_VAR: 'other',
]
if (project.hasProperty('dart-defines')) {
dartEnvironmentVariables = dartEnvironmentVariables + project.property('dart-defines')
.split(',')
.collectEntries { entry ->
def pair = URLDecoder.decode(entry).split('=')
[(pair.first()): pair.last()]
}
}
複製程式碼
如果發現到獲取不了,可以通過列印project.property('dart-defines')
內容,看看是什麼編碼格式,或者查閱最新的文件。
獲取到渠道名後,就是配置apk名稱了,這裡只在正式環境才輸出自定義包名。
android{
applicationVariants.all { variant ->
variant.outputs.all { output ->
if(variant.buildType.name == "release"){
def newApkName="${dartEnvironmentVariables.ANDROID_CHANNEL}_app_v${defaultConfig.versionName}_${defaultConfig.versionCode}.apk"
outputFileName = new File(newApkName)
}
}
}
}
複製程式碼
ok,這樣打包輸出的包名就自帶渠道了。路徑應該是專案目錄/build/app/outputs/apk/release
。
自動化打包
通過上面方式,每次打包只能打一個渠道包,那麼多應用商店,累啊。
在專案根目錄,寫指令碼build_channel.sh
,內容如下。
flutter build apk --dart-define=ANDROID_CHANNEL=$1
cd 專案根目錄/build/app/outputs/apk/release
mv *.apk 其他目錄
複製程式碼
其中專案根目錄需要更改成自己實際專案目錄。由於每次打包會覆蓋之前的apk,所以打包完一個apk,需要移動到其他資料夾。
再建立指令碼build_apk.sh
。
build_channel.sh xiaomi
build_channel.sh huawei
build_channel.sh meizu
build_channel.sh vivo
build_channel.sh oppo
build_channel.sh yingyongbao
build_channel.sh m360
複製程式碼
根據自己的渠道,按上面格式新增即可。
最後通過執行build_apk.sh
指令碼就可以了。另外注意兩個指令碼的許可權問題chomd 777 xxx
。