编译打包篇 — 灵活使用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文件中。

buildconfig.png

这成功又勾起了我的好奇心,为啥在.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中去,达到动态改变配置的效果。

你可能感兴趣的:(编译打包篇 — 灵活使用BuildConfig)