React Native 0.70.x如何从本地安卓源码(ReactAndroid)构建

在 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")
          }
      }
  }

开始试运行

  1. 清理之前的缓存: 终端执行./gradlew clean
  2. 然后运行:终端执行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文件。

应用源码改动

上面只记录了如何从源码编译,当你成功之后,如果你期望你修改的源码可以应用到项目中,可以在生产使用,那有两种解决方案:

  1. 发布你自己的ReactNative版本,然后在package.json修改依赖。那就按照教程来:github.com/facebook/re...
  2. yarn补丁管理: yarn patch-package react-native,就是把你之前在node_modules/react-native/当成个补丁提交,这样可以跟随着项目一起,但缺点在于改动的点不够明确
相关推荐
蓝婷儿44 分钟前
第二章:CSS秘典 · 色彩与布局的力量
前端·css
Wyc724092 小时前
HTML:入门
前端·html
Sunny_lxm2 小时前
自定义列甘特图,原生开发dhtmlxgantt根特图,根据数据生成只读根特图,页面展示html demo
前端·html·甘特图·dhtmlxgantt
熊猫钓鱼>_>3 小时前
建筑IT数字化突围:建筑设计企业的生存法则重塑
前端·javascript·easyui
GISer_Jing5 小时前
前端性能指标及优化策略——从加载、渲染和交互阶段分别解读详解并以Webpack+Vue项目为例进行解读
前端·javascript·vue
不知几秋5 小时前
数字取证-内存取证(volatility)
java·linux·前端
水银嘻嘻6 小时前
08 web 自动化之 PO 设计模式详解
前端·自动化
Zero1017138 小时前
【详解pnpm、npm、yarn区别】
前端·react.js·前端框架
&白帝&8 小时前
vue右键显示菜单
前端·javascript·vue.js
Wannaer8 小时前
从 Vue3 回望 Vue2:事件总线的前世今生
前端·javascript·vue.js