在 React Native 开发过程中,通常我们依赖于已发布 React-Native
的 NPM 包。然而,在某些特定情况下,比如虽然RN已经修复了一些bug,但是你的项目无法立刻升级,这就需要从源代码构建 React Native,特别是在进行深度定制或者调试时。本文将介绍如何从 React Native 的 Android 部分源码 ReactAndroid
来构建 React Native。
如果你是React-Native
比较新的版本(版本号大于0.72.x
),可能本文对你的帮助有限,你只需要按照官方的文章进行即可:reactnative.dev/contributin...,当然你也可以继续看看,或许构建的错误都有共同之处。
接下来就来说说,旧版本的该怎么操作:第一步找官方教程,第二步解决官方教程坑。
按照官方教程操作
如果你是直接搜索,大概率找到的是新版本的构建,而旧版本通常比较难找到,找的的可能也是中文官网上比较老的版本说明,这里贴下文章:github.com/facebook/re...
下面只挑重点的来讲,默认你已经有了自己的RN项目,现在只是希望自己的项目能用到node_modules里面的源码,从而达到自己修改源码就可以应用到自己项目。
下面我就概括一下:
安装并设置NDK和SDK
**步骤1:**通过终端设置环境变量。
- bash:
<font style="color:rgb(31, 35, 40);">.bash_profile</font>
或者<font style="color:rgb(31, 35, 40);">.bashrc</font>
- zsh:
<font style="color:rgb(31, 35, 40);">.zprofile</font>
或者<font style="color:rgb(31, 35, 40);">.zshrc</font>
例子:
plain
export ANDROID_SDK=/Users/your_unix_name/android-sdk-macosx
export ANDROID_NDK=/Users/your_unix_name/android-ndk/android-ndk-r20b
步骤2: 修改你的<font style="color:rgb(31, 35, 40);">local.properties</font>
,路径是你项目下<font style="color:rgb(31, 35, 40);">android/local.properties</font>
,没有就新建
添加内容(如果已经设置就忽略):
plain
sdk.dir=/Users/your_unix_name/android-sdk-macosx
ndk.dir=/Users/your_unix_name/android-ndk/android-ndk-r20b
如果你没有这两个路径或者不知道下载过没,打开Android Studio去找。
修改项目安卓打包的相关配置
- 修改
<font style="color:rgb(31, 35, 40);">android/build.gradle</font>
,增加下载相关依赖
增加两行配置(带+号的),不过一般能的项目都有了,有了就别改动了,这个配置只是下载使用的
plain
buildscript {
// ...
dependencies {
// Make sure that AGP is at least at version 7.x
classpath("com.android.tools.build:gradle:7.0.4")
+ classpath("com.facebook.react:react-native-gradle-plugin")
+ classpath("de.undercouch:gradle-download-task:5.0.1")
}
}
- 修改
<font style="color:rgb(31, 35, 40);">android/settings.gradle</font>
,引用<font style="color:rgb(31, 35, 40);">node_modules/react-native/ReactAndroid</font>
目录的源码
在文件底部增加下面的代码:
plain
// ...省略其他
include(":ReactAndroid")
project(":ReactAndroid").projectDir = new File('../node_modules/react-native/ReactAndroid')
//注意:官方是没有hermes-engine,但是我的项目有用到所以也添加,你可以先不加,打包如果报错之后再加这两行
include(':ReactAndroid:hermes-engine')
project(':ReactAndroid:hermes-engine').projectDir = new File(rootProject.projectDir, '../node_modules/react-native/ReactAndroid/hermes-engine')
- 修改
android/app/build.gradle
,项目用<font style="color:rgb(31, 35, 40);">node_modules/react-native/ReactAndroid</font>
目录的源码构建
找到<font style="color:rgb(31, 35, 40);">dependencies</font>
配置,把 <font style="color:rgb(31, 35, 40);">implementation 'com.facebook.react:react-native:+'</font>
改成 <font style="color:rgb(31, 35, 40);">implementation project(':ReactAndroid')</font>
plain
dependencies {
//implementation 'com.facebook.react:react-native:+' 需要注释掉
implementation project(':ReactAndroid')
// ...
}
还是同一个文件,找到configurations.all
,增加下面的配置:
plain
configurations.all {
resolutionStrategy {
dependencySubstitution {
//这主要是让第三方React Native库,也使用我们指定的本地库,不然它们会使用预编译的库,会报错
substitute module("com.facebook.react:react-native:+") with project(":ReactAndroid")
}
}
}
开始试运行
- 清理之前的缓存: 终端执行
./gradlew clean
- 然后运行:终端执行
yarn android
如果你能运行,恭喜你,那真是太过顺利了,不然可能会出现一些问题,你可以继续往下看看
解决打包过程中的失败
打包过程中,任务下载各种包失败
Node包中使用的库也会依赖各种包,这种任务在你yarn android
的日志中都会体现:
plain
//ReactAndroid相关的下载任务
Task :ReactAndroid:downloadFmt UP-TO-DATE
Download https://github.com/fmtlib/fmt/archive/6.2.1.tar.gz
//react-native-reanimated库相关的下载任务
Task :react-native-reanimated:downloadBoost UP-TO-DATE
Download https://boostorg.jfrog.io/artifactory/main/release/0.70.10/source/boost_1_76_0.tar.gz
如果发现包下载失败,自己复制url
到浏览器试试,检查是否可以访问,可能需要科学上网,如果科学砂锅女王还是不行就去镜像网站上查找,然后去node_modules
对应的目录下修改<font style="color:rgb(31, 35, 40);">android/build.gradle</font>
,可以指定可以下载的路径,这里情况分两种,一种是你依赖的第三方库(比如:react-native-reanimated),一种是ReactAndroid任务
- 前者你去
node_modules/<font style="color:rgb(31, 35, 40);">react-native-reanimated/android/build.gradle</font>
修改对应的url
,一定要能下下来包,下载下来的内容在node_modules/<font style="color:rgb(31, 35, 40);">react-native-reanimated/android/build/downloads</font>
中,你也可以检查是否下载下来的有内容 - 后者要到
node_modules/react-native/ReactAndroid/build.gradle
修改,原理都是一样的
buildHermes失败
在日志中会出现对应任务,如果这个任务跑过,基本就成功了
plain
Task :ReactAndroid:hermes-engine:buildHermes
只需要关注失败!!也就是 error
提示,警告不用管。
之前我碰到过一个异常:
plain
node_modules/react-native/sdks/hermes/lib/Support/Semaphore.cpp:35:3:
error: use of undeclared identifier 'assert' 35 | assert(semPtr_ != nullptr && "sem_open should have succeeded");
跟GPT
交流了一下发现是node_modules/react-native/sdks/hermes/lib/Support/Semaphore.cpp
代码中使用了 assert
,但没有包含相应的头文件。在 C++ 中,assert
是定义在 <cassert>
(C++)或 <assert.h>
(C)的头文件中的。如果这个头文件没有被正确包含,就会导致该错误。
但是当你欣喜若狂去修改了却发现并没有用,因为每次yarn android
都会重新下载sdks/hermes
的内容,所以要先把hermes
的内容全都复制出来,修改Semaphore.cpp
文件,然后打包成tar
文件,放到自己服务器的上,再按照第一步的方式去修改任务的下载链接。
hermes
的下载 task :ReactAndroid:hermes-engine:downloadHermes UP-TO-DATE,所以要去查找downloadHermes
这个任务,最后发现是ReactAndroid/hermes-engine/build.gradle
中的,所以找到并修改即可。
最后还要测试一下生成模式下是否成功,还遇到过生成下载的hermes
不是最新的,需要修改hermes
下载包名
plain
task downloadHermes(type: Download) {
- dest(new File(downloadsDir, "hermes.tar.gz"))
+ dest(new File(downloadsDir, "myHermes.tar.gz"))
}
总结
上面只是总结了自己所遇到的疑难杂症,基本上所有的问题通常出现在库的第三方依赖,所以要学会去各个库修改第三方依赖,也就是修改他们的build.gradle
文件。
应用源码改动
上面只记录了如何从源码编译,当你成功之后,如果你期望你修改的源码可以应用到项目中,可以在生产使用,那有两种解决方案:
- 发布你自己的ReactNative版本,然后在
package.json
修改依赖。那就按照教程来:github.com/facebook/re... - 用
yarn
补丁管理:yarn patch-package react-native
,就是把你之前在node_modules/react-native/
当成个补丁提交,这样可以跟随着项目一起,但缺点在于改动的点不够明确