Flutter 多環境、多渠道自動打包

新小夢發表於2021-08-05

本文主要解決在多環境(測試環境,開發環境等),多渠道情況下,如何優雅快速的進行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引數。

image-20210804153902776

配置run args,內容和上面一致。

image-20210804153941751

如果需要配置多個環境,例如開發環境,測試環境,正式環境,也可以通過這種方式來進行,避免手動修改程式碼,出錯。

  1. 複製已有的配置內容
  2. 修改配置名稱name,例如生產環境:main-prod
  3. 修改不同環境引數內容

image-20210804154323144

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-definesvalue是會進行加密的,所以需要進行解密,而且不同版本的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

相關文章