[React Native] react-native-config 在js层获取参数为空

2,817 阅读1分钟

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的路径的获取由如下两部分获取到的:

  1. 取配置项 R.string.build_config_package 这个配置的参数
  2. 如果配置项不存在,则取 getApplicationContext().getPackageName()

而我们知道,getPackageName 返回的是 applicationId{.suffix}。如果不配置build_config_package这个参数,那么默认取得的getPacakgeName的,所以,如果反射BuildConfig.class 路径失败

而在我们项目中。AndroidManifest.xml中配置的packageNameapplicationId 不一致, 所以在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"
        
    }
}