在React Native开发中,react-native-config 是一个非常实用的三方库。
发现问题
但应用中却遇到了一个问题:
- 在
android/app/build.gradle中,是可以取到.env文件中定义的配置的参数 - 但在
javascript中获取的参数却为空
javascript 层调用的方法如下:
import Config from 'react-native-config'
Config.API_URL
console.log(`Config from .env:`, Config)
而NativeModule的变量来自于ReactContextBaseJavaModule 子类的 getConstants() 方法
分析源码
查看一下react-native-config java层实现代码:
node_modules/react-native-config/android/src/main/java/com/lugg/ReactNativeConfig/ReactNativeConfigModule.java:
public class ReactNativeConfigModule extends ReactContextBaseJavaModule {
public ReactNativeConfigModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@Override
public String getName() {
return "ReactNativeConfig";
}
@Override
public Map<String, Object> getConstants() {
final Map<String, Object> constants = new HashMap<>();
try {
Context context = getReactApplicationContext();
int resId = context.getResources().getIdentifier("build_config_package", "string", context.getPackageName());
String className;
try {
className = context.getString(resId);
} catch (Resources.NotFoundException e) {
className = getReactApplicationContext().getApplicationContext().getPackageName();
}
Class clazz = Class.forName(className + ".BuildConfig");
Field[] fields = clazz.getDeclaredFields();
for(Field f: fields) {
try {
constants.put(f.getName(), f.get(null));
}
catch (IllegalAccessException e) {
Log.d("ReactNative", "ReactConfig: Could not access BuildConfig field " + f.getName());
}
}
}
catch (ClassNotFoundException e) {
Log.d("ReactNative", "ReactConfig: Could not find BuildConfig class");
}
return constants;
}
}
分析代码,constants 是通过反射编译生成BuildConfig.class 对应的值
而BuildConfig的路径的获取由如下两部分获取到的:
- 取配置项
R.string.build_config_package这个配置的参数 - 如果配置项不存在,则取
getApplicationContext().getPackageName()
而我们知道,getPackageName 返回的是 applicationId{.suffix}。如果不配置build_config_package这个参数,那么默认取得的getPacakgeName的,所以,如果反射BuildConfig.class 路径失败
而在我们项目中。AndroidManifest.xml中配置的packageName 和 applicationId 不一致, 所以在javascript中无法读取到配置的参数。需要指定编译之后的路径
解决办法
添加build_config_package参数, 指定BuildConfig.class的绝对路径
android {
defaultConfig {
applicationId project.env.get("APP_ID")
versionCode project.env.get("APP_VERSION_CODE").toInteger()
versionName project.env.get("APP_VERSION_NAME")
// for react-native-config
resValue "string", "build_config_package", "your AndroidManifest.xml package name"
}
}