编译打包篇 — 灵活使用BuildConfig
看完本篇将了解到:
第一,如何在BuildConfig文件中构建自定义的属性;
第二,如何利用命令行修改这些自定义属性,从而构建不同版本的安装包。(比如正式环境带Log日志打印的包等等)
1 起因
最近翻看公司项目的时候,看到了以下代码
import Config from 'react-native-config';
const developConfig = {
api: {
protocol: 'http',
host: 'test-api.anystories.app',
},
};
const releaseConfig = {
api: {
protocol: 'https',
host: "api.anybooks.live",
},
};
let config = releaseConfig;
// 对,就是这一行代码,说得就是你
if (Config.ENV === "dev" || __DEV__) {
config = developConfig;
}
export {
config,
};
注意上面那行被标记的代码,是不是有点好奇,这个config.ENV中的ENV是怎么来?
2 react-native-config的使用简介
于是乎就去了解react-native-config
的用法,官网地址如下:react-native-config官网。
先简单介绍一下它的用法,先在项目根目录定义一个文件叫做.dev
,然后在文件中随便定义几个变量:
API_URL=https://myapi.com
GOOGLE_MAPS_API_KEY=abcdefgh
获取变量的方法如下:
import Config from "react-native-config";
Config.API_URL; // 'https://myapi.com'
Config.GOOGLE_MAPS_API_KEY; // 'abcdefgh'
此时,应该能明白ENV其实就是我们在.dev
文件中定义的一个变量,其实这是RN与Android交互中暴露出来的常量值,往后有机会再做一下介绍。
3 为何出现在BuildConfig.java文件中
而后,又发现一个问题,这个在.dev
文件中定义的变量,会直接出现在Android编译项目时产生的BuildConfig.java
文件中。
这成功又勾起了我的好奇心,为啥在.dev
文件中的变量会出现在BuildConfig.java
文件中呢?
这就得看这个RN库的Android端代码做了什么,于是去找到源码,这个得从Android项目中build.gradle
构建脚本中说起。在我们使用react-native-config
库后,在build.gradle
中会引入如下一行代码:
apply from: project(':react-native-config').projectDir.getPath() + "/dotenv.gradle"
这里是直接把dotenv.gradle
脚本引入,然后我们找到dotenv.gradle文件,里面有段脚本如下:
def loadDotEnv(flavor = getCurrentFlavor()) {
def envFile = ".env"
if (System.env['ENVFILE']) {
envFile = System.env['ENVFILE']
println("zp_test system env")
} else if (System.getProperty('ENVFILE')) {
envFile = System.getProperty('ENVFILE')
println("zp_test system getProperty")
} else if (project.hasProperty("envConfigFiles")) {
// use startsWith because sometimes the task is "generateDebugSources", so we want to match "debug"
project.ext.envConfigFiles.any { pair ->
if (flavor.startsWith(pair.key)) {
envFile = pair.value
return true
}
}
} else if (project.hasProperty("defaultEnvFile")) {
envFile = project.defaultEnvFile
}
...
}
loadDotEnv()
android {
defaultConfig {
project.env.each { k, v ->
def escaped = v.replaceAll("%","\\\\u0025")
buildConfigField "String", k, "\"$v\""
resValue "string", k, "\"$escaped\""
}
}
}
以上脚本文件就不一一解释了,大致的逻辑就是:
1 在系统环境变量中去找寻一个名叫
ENVFILE
的环境变量,如果存在就直接赋值给环境变量。
2 如果不存在就查看系统属性中是否存在。
3 如果不存在就查看项目的defaultEnvFile
属性。
4 找到并遍历这个文件,写入BuildConfig
中。
写入到buildconfig
中的代码:
buildConfigField "String", k, "\"$v\""
三个参数依次为写入的字段类型,写入的字段名,写入的字段值。而指定环境变量,这里涉及到一个命令行:export xxx=.dev
;这时环境变量xxx就被指定了,此时编译打包xxx环境变量就会一直指向.dev
。比如上面代码中的ENVFILE
。
4 总结
第一步,写好脚本文件获取自定义环境变量(比如ENVFILE
),脚本文件主要有两个作用
- 第一,找到环境变量所指文件;
- 第二,遍历文件中的所有字段,并利用
buildConfigField "String", k, "\"$v\""
这句代码将文件中的值写入到BuildConfig中去。
第二步,用export
命令指定当前ENVFILE
为哪个文件,比如export ENVFILE=.env
。
第三步,编译打包;
此时,就算打release包,也可以利用export命令指定相应变量的值至BuildConfig中去,达到动态改变配置的效果。