看完本篇將了解到:
第一,如何在BuildConfig文件中構(gòu)建自定義的屬性;
第二,如何利用命令行修改這些自定義屬性,從而構(gòu)建不同版本的安裝包。(比如正式環(huán)境帶Log日志打印的包等等)
1 起因
最近翻看公司項(xiàng)目的時(shí)候,看到了以下代碼
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;
// 對(duì),就是這一行代碼,說(shuō)得就是你
if (Config.ENV === "dev" || __DEV__) {
config = developConfig;
}
export {
config,
};
注意上面那行被標(biāo)記的代碼,是不是有點(diǎn)好奇,這個(gè)config.ENV中的ENV是怎么來(lái)?
2 react-native-config的使用簡(jiǎn)介
于是乎就去了解react-native-config的用法,官網(wǎng)地址如下:react-native-config官網(wǎng)。
先簡(jiǎn)單介紹一下它的用法,先在項(xiàng)目根目錄定義一個(gè)文件叫做.dev,然后在文件中隨便定義幾個(gè)變量:
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'
此時(shí),應(yīng)該能明白ENV其實(shí)就是我們?cè)?code>.dev文件中定義的一個(gè)變量,其實(shí)這是RN與Android交互中暴露出來(lái)的常量值,往后有機(jī)會(huì)再做一下介紹。
3 為何出現(xiàn)在BuildConfig.java文件中
而后,又發(fā)現(xiàn)一個(gè)問(wèn)題,這個(gè)在.dev文件中定義的變量,會(huì)直接出現(xiàn)在Android編譯項(xiàng)目時(shí)產(chǎn)生的BuildConfig.java文件中。

這成功又勾起了我的好奇心,為啥在.dev文件中的變量會(huì)出現(xiàn)在BuildConfig.java文件中呢?
這就得看這個(gè)RN庫(kù)的Android端代碼做了什么,于是去找到源碼,這個(gè)得從Android項(xiàng)目中build.gradle構(gòu)建腳本中說(shuō)起。在我們使用react-native-config庫(kù)后,在build.gradle中會(huì)引入如下一行代碼:
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 在系統(tǒng)環(huán)境變量中去找尋一個(gè)名叫
ENVFILE的環(huán)境變量,如果存在就直接賦值給環(huán)境變量。
2 如果不存在就查看系統(tǒng)屬性中是否存在。
3 如果不存在就查看項(xiàng)目的defaultEnvFile屬性。
4 找到并遍歷這個(gè)文件,寫(xiě)入BuildConfig中。
寫(xiě)入到buildconfig中的代碼:
buildConfigField "String", k, "\"$v\""
三個(gè)參數(shù)依次為寫(xiě)入的字段類型,寫(xiě)入的字段名,寫(xiě)入的字段值。而指定環(huán)境變量,這里涉及到一個(gè)命令行:export xxx=.dev;這時(shí)環(huán)境變量xxx就被指定了,此時(shí)編譯打包xxx環(huán)境變量就會(huì)一直指向.dev。比如上面代碼中的ENVFILE。
4 總結(jié)
第一步,寫(xiě)好腳本文件獲取自定義環(huán)境變量(比如ENVFILE),腳本文件主要有兩個(gè)作用
- 第一,找到環(huán)境變量所指文件;
- 第二,遍歷文件中的所有字段,并利用
buildConfigField "String", k, "\"$v\""這句代碼將文件中的值寫(xiě)入到BuildConfig中去。
第二步,用export命令指定當(dāng)前ENVFILE為哪個(gè)文件,比如export ENVFILE=.env。
第三步,編譯打包;
此時(shí),就算打release包,也可以利用export命令指定相應(yīng)變量的值至BuildConfig中去,達(dá)到動(dòng)態(tài)改變配置的效果。