本文完整阅读约需 13 分钟,如时间较长请考虑收藏后慢慢阅读~

不久前我接手了一个React Native项目,需要对应用的逻辑进行修改。然而在我自信满满地修改完js文件,放入模拟器执行时,却发现所有修改均未生效。折腾来折腾去才发现是这个工程已经开启了生产模式,然而应该如何返回到调试模式呢?

0x01

React Native为了提升应用执行性能,会在生产模式启动时对所有的资源文件以及相关代码打包后存储在app/src/main/assets目录。

而当其处于调试模式的时候,需开启服务器进程,并可通过模拟器内双击R键的方式实现实时刷新,而不需要重新构建。

我所接手的项目据说已经开启了生产模式(但对方并不知道如何关闭)。我尝试着通过清除缓存目录的方法来接触生产模式,然而在简单清除该目录后,却发现应用出现闪退情况。

0x02

我尝试阅读React Native官方文档,希望从中找到相关的资料,但无论是搜索debug modecacheassetsbundle,均未能得到任何结果。

0x03

于是我在React Native官方GitHub仓库中搜索包含index.android.bundle的Issue,搜索到了这一篇:
facebook/react-native issues#22076

0x04

按照Issue中的方法,我注释掉了MainApplication.java中的import com.facebook.react.BuildConfig;,删除app/src/main/assets目录中所有文件,并尝试重新编译。
这一次项目终于回到了调试模式,应用行为与我在js文件中所描述的一致,也可以在服务器未开启时显示红屏警告。

0x05

根据Issue中的指引,我尝试利用AndroidStudio(IDEA)自带的反编译功能对com.facebook.react.BuildConfig包进行反编译,拿到的结果如图所示:

可以看见,该包重载了BuildConfig类,并将DEBUG属性设置为False。

顺藤摸瓜Inspect下去,我们会发现该属性在MainApplication.javagetUseDeveloperSupport()重载方法中被调用,该部分代码为React Native自动生成。

而当我们注释掉com.facebook.react.BuildConfig包后,再度往下Inspect,会发现当这个包被注释后,所引用的类为app/build/generated/source/buildConfig/debug/{your.package.name}/buildConfig.java,而其中将DEBUG属性设置为了True。

0x06

一切迷惑就此真相大白。
我们也可以回归到这篇文章的主题:如何切换React Native的生产模式和调试模式呢?

从调试模式切换到生产模式

  1. 构建assets/index.{platform}.bundle文件
    这里以Android为例。控制台切换到项目根目录,执行以下命令:
react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --assets-dest app/src/main/res/

注意,app/src/main/res/assets目录必须提前建立,否则会提示找不到目录。

  1. 构建结束后,在MainApplication.java中引入com.facebook.react.BuildConfig包:
import com.facebook.react.BuildConfig;

最后,在Android Studio中编译执行,即可切换到生产模式

从生产模式切换回调试模式

  1. 删除assets/index.{platform}.bundle文件

    该步骤为可选项,不删除也可以,单纯是为了避免文件冗余,以及造成维护上的迷惑。

  2. 注释掉import com.facebook.react.BuildConfig;这一行代码

  3. 在项目根目录下执行react-native start开启本地调试服务器

同上,在Android Studio中编译执行,即可切换到调试模式


附:

除了直接修改MainAppliction.java以外,还有一种方法,即利用Gradle的BuildConfig,该方法可以轻松实现调试模式&生产模式配置化。
1. 修改app/build.gradle文件,在最上面加入以下配置:

def debugMode = "true"

task generateBundle (type:Exec) {
    if (debugMode.compareTo("debug")) {
        commandLine './buildDebug.sh'
    } else {
        commandLine './buildProduction.sh'
    }
}

如果是Windows,将.sh修改为.bat,本文默认你已经是一位*NIXer,或已经掌握Windows的命令行操作,因此不扩展说明Windows下的配置方法。

  1. 同时在该文件android -> buildTypes -> debug下加入以下配置:
debug {
    buildConfigField "boolean", "DEBUG_MODE", debugMode
}
  1. app目录下建立两个文件,命名为buildDebug.shbuildProduction.sh并给与执行权限:
#!/bin/bash
# buildDebug.sh
cd ..
screen -dm react-native start
#!/bin/bash
# buildProduction.sh
cd ..
react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output app/src/main/assets/index.android.bundle --assets-dest app/src/main/res/

建议在编辑完成后,执行测试一下,以避免出现预料之外的故障,提高排错难度。

  1. 在AndroidStudio中点击菜单栏的Build -> Edit Configurations...,打开你需要编译的包,在Before Launch选项处点击加号,选择Run Gradle Task,并选择app作为Gradle Project,第一步加入的generateBundle作为Tasks,其他默认。

  2. 重新同步Gradle项目,构建并运行。

这样子,我们只需要修改第一步中debugMode的值(true or false),即可实现生产模式和调试模式的切换!