Flutter 多环境、多渠道自动打包
本文主要解决在多环境(测试环境,开发环境等),多渠道情况下,如何优雅快速的进行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
。
转载自:https://juejin.cn/post/6992750033338630158