RN问题集合记录

  • Post author:
  • Post category:其他


更新说明

日期 更新内容
2022-05-09 添加RN库需要更新时的注意操作
2021-08-21 更新RN项目编译时的问题
2021-08-17 编译原生项目gradle报错



1. 编译错误问题



1.1. 运行node命令失败

错误信息:

ReactNative:Running ‘[node, -e, console.log(require(‘react-native/cli’).bin);]’ command failed. (Cannot run program “node”)

出现场景:

该错误信息是在原来项目完全正常的情况下,重新打开运行时就报错了,导致了原生的android项目无法正常编译。

但是如果是在RN项目中直接运行命令

yarn android

是可以正常编译和安装程序的

。所以这里可以很明确这个问题并不是真的问题。

解决方案:

以下是查询到网络上的一些说明,作为参考提供:

  1. github issue:https://github.com/react-native-community/cli/issues/1226
  2. stackoverflow:https://stackoverflow.com/questions/61922174/react-native-on-android-cannot-run-program-node-error-2-no-such-file-or-dir

这边尝试解决方案如下可以解决此问题(参考自stackoverflow):

I’m on my Mac, and i solve this by close the android studio completely(close the process), and restart it.

  1. 基于macOs环境,退出当前所有的android项目,确保整个AS的进程完全退出(

    注意不要只退出当前的项目,是所有的AS项目都需要退出,整个进程需要关闭

  2. 重新启动相关项目,重新编译即可



1.2. 重命名应用模块名称后无法运行

错误信息:

Build file 'xxx/node_modules/react-native-reanimated/android/build.gradle' line: 11

A problem occurred evaluating project ':react-native-reanimated'.
> Project with path ':app' could not be found in project ':react-native-reanimated'.

出现场景:

使用全新的一个应用模块,代替RN项目默认创建的模块运行,在

yarn android

中无法运行起新的应用模块;或者是将原应用模块重命名了,导致编译报错或无法运行起来。此问题根据错误信息也是可以定位到修改的位置

RN运行起android项目时,会通过gradle脚本读取固定模块

:app

下的一些参数配置,所以只有

:app

的模块名称才能被运行起来。可以通过修改

node_module

文件夹下的gradle文件,调整运行的应用模块

解决方案:

  1. 打开gradle文件:

    xxx/node_modules/react-native-reanimated/android/build.gradle
  2. 修改以下的

    :app

    模块名称为需要运行的实际应用模块名称
def engine = "jsc"
//这里限制死了必须是app的模块名称,并且该模块中必须有ext.react.enableHermes的字段
if (project(':app').ext.react.enableHermes) {
    engine = "hermes"
}

注意:

在更新的版本中,可能已经不使用此方式限制了应用的名称

,首先对以上提到的

enableHermes

的检查,已经替换为了判断包含了插件

com.android.application

时才进行读取该字段并判断,也就是通过插件直接来区分是一个应用还是一个依赖库了

def detectJsRuntime() {
    def runtimeType = "jsc"
    rootProject.getSubprojects().forEach({project ->
        //这里已经不再指定固定的应用模块了
        if (project.plugins.hasPlugin("com.android.application")) {
            if (project.ext.react.enableHermes) {
                runtimeType = "hermes"
            }
        }
    })
    return runtimeType
}

但是与此同时,会在另外的地方去指定应用的名称:

abstract class replaceSoTask extends DefaultTask {
    //这里是强制指定了应用的模块
    public static String appName = ":app"
    public static String buildDir = "../../../android/app/build"
    public static String fbjniVersion = "0.3.0"
    //...
}



1.3. 模块中未配置

enableHermes

的字段

RN会根据配置信息自行使用JSC或者是Hermes的JS引擎,但是默认的RN项目实际上都是使用的JSC的引擎。在RN的官网中有提及需要在项目中配置上

enableHermes

的字段

//app模块中的build.gradle文件
project.ext.react = [
        enableHermes: false,  // clean and rebuild if changing
]

很明显这里就是使用了JSC的引擎,而且不人为强制修改是不会变的。但是在

node_modules

中的JS引擎项目中,有使用了这个参数信息进行判断。当不存在这个字段时,就会报错。

def engine = "jsc"
//这里限制死了必须是app的模块名称,并且该模块中必须有ext.react.enableHermes的字段
if (project(':app').ext.react.enableHermes) {
    engine = "hermes"
}

解决此问题有两个方式,其中一个方式是按官网的要求,在模块的build.gradle中添加上该字段的配置。

方式二是修改此处的脚本,让其不强制依赖此字段即可。

def engine = "jsc"
//如果存在此字段才进行使用,否则不需要做任何修改
if (project(':app').ext.has("react")
        && project(':app').ext.react.has("enableHermes")) {
    def enableTag = project(':app').ext.react.enableHermes
    if (enableTag != null && enableTag) {
        engine = "hermes"
    }
}

注意:有部分 RN 使用到的依赖库的 gradle 中是只关心

application

模块,如果是

library

的话,不需要处理这个字段。

def runtimeType = "jsc"
rootProject.getSubprojects().forEach{project ->
    //这里是检查了只有 application 插件的模块才会处理
    if (project.plugins.hasPlugin("com.android.application")) {
        if (project.ext.react.enableHermes) {
            runtimeType = "hermes"
        }
    }
})



1.4. Android原生应用项目路径名称问题

RN默认创建的android应用是是存放于

android

文件夹下的,所以在默认生成的

node_module

中的gradle文件是以该文件夹为准的。当应用所在文件路径不正确时,可能会报以下错误:

FAILURE: Build failed with an exception.

* Where:
Script 'xxx/node_modules/@react-native-community/cli-platform-android/native_modules.gradle' line: 248

* What went wrong:
A problem occurred evaluating script.
> React Native CLI failed to determine Android project configuration. This is likely due to misconfiguration. Config output:

根据提示的信息和错误的位置,可以查找到在文件

xxx/node_modules/@react-native-community/cli-platform-android/native_modules.gradle

中,有以下的代码,在这里是读取了项目中的

android

项目,然后再进行了后续操作,如果不存在

android

的项目,则会报错。

    def dependencies = json["dependencies"]
    //这里读取的是android路径下的项目,需要调整为实际项目所在的文件夹名称
    def project = json["project"]["android"]

    if (project == null) {
      throw new Exception("React Native CLI failed to determine Android project configuration. This is likely due to misconfiguration. Config output:\n${json.toMapString()}")
    }


但是很遗憾在实际操作中,这里的信息读取了json配置后得到的,而json信息是通过运行命令得出来的,无法单纯修改这里的文件夹名称来调整加载的android项目

,所以

将原生项目引用RN项目中的node_modules并使用其依赖,原生项目的存储位置只能是命名为android的文件夹

建议将当前项目所有内容复制到新的文件夹下,并将该文件夹重命名为

android



1.5. 依赖版本太低无法加载ReactApplication

报错信息如:

/Users/Lincoln/android/sdk_demo/app/src/main/java/cn/xlink/sdk/demo/ui/module/main/DemoApplication.java:63: 错误: 找不到符号
    public ReactNativeHost getReactNativeHost() {
           ^
  符号:ReactNativeHost
  位置:DemoApplication

排除掉常规的错误,可以查看依赖库中使用的React Native的版本号。当前依赖是期望版本为0.64.1。但是实际上查看依赖库中的版本号时,可以发现是0.20.1,而在该低版本中是不存在相应的类的。很明显该版本并不是我们需要的版本。尽管依赖库中我们是使用了+号表示版本号:

implementation "com.facebook.react:react-native:+"

但是因为我们是依赖本地的

node_modules

中的文件,该文件夹中只有0.64.1版本,所以是不应该出现更低版本的。这种情况很可能是依赖库的地址错误,我们再次确认一下全局的依赖库,如现该相对地方也是指向本地的

node_modules

allprojects {
    repositories {
        maven {
            url("../node_modules/react-native/android")
        }
        maven {
            url("../node_modules/jsc-android/dist")
        }
    }
}


但是最重要的坑来了,以上的写法不能是无法正确指向本地的node_modules的

。我们必须类似RN原项目中创建时使用的写法才行:

allprojects {
    repositories {
        mavenLocal()
        maven {
            //这里必须添加上$rootDir
            url("$rootDir/../node_modules/react-native/android")
        }
        maven {
            //这里必须添加上$rootDir
            url("$rootDir/../node_modules/jsc-android/dist")
        }
    }
}

实际上因为当前的项目已经是主项目了,该地址也是当前的地址,与上述的写法并没有太大的差别。这里唯一的可能是运行脚本的地方,

不在当前项目中,所以导致了读取出来的地址是不正确的,而

$rootDir

是能指向一个绝对地址的。这里特别记录一下这个错误信息。

附上一个与之相关的问题链接,但是该问题与上述描述中的问题不是相同的情况,仅作参考:

compile ‘com.facebook.react:react-native:+’ defaults to 0.20.1



2. 运行时问题



2.1. RN页面UI元素突然消失不可见

在实际使用过程中,发现存在一个特殊的情况,RN的页面可以正常加载,UI元素也可以正常显示出来。但是在显示后约5秒后就消失了,该问题在IOS平台上并不会出现,只在Andriod平台上出现,并且根据前端同事的反馈即使回退版本也是存在该问题的。

可以确认在此之前的测试页面是正常的能显示UI元素也不会出现,整个过程中不管是JS引擎还是RN页面或者是原生系统都没有报出任何错误信息,非常感觉到诡异。

在经过确认确实与RN页面无关后,再重新检查原生这边的实现,发现问题是:

承载了ReatRootView的原生容器中,使用了NestedScrollView包裹起来了

,就是因为这个导致页面会在几秒后突然就消失掉了,只要去掉外部包裹的ScrollView即可以解决这个问题。特此记录一下。



2.2. 编译成功后运行到加载RN页面时,无法正确加载页面报错

报错信息可能如下:

java.lang.UnsatisfiedLinkError: dlopen failed: library "libjsc.so" not found
    at java.lang.Runtime.load0(Runtime.java:938)
    at java.lang.System.load(System.java:1632)
    at com.facebook.soloader.SoLoader$1.load(SoLoader.java:400)
    at com.facebook.soloader.DirectorySoSource.loadLibraryFrom(DirectorySoSource.java:77)
    at com.facebook.soloader.DirectorySoSource.loadLibrary(DirectorySoSource.java:50)
    at com.facebook.soloader.ApplicationSoSource.loadLibrary(ApplicationSoSource.java:89)

该信息是比较明确的,就是缺少了

jsc

的so库,该库是JS引擎是必不可少的。这时我们可以通过反编译APK确认在APK的lib中是否存在该so库。直接在AS中打开build文件夹下的编译生成的apk文件即可检查。

如果出现该问题,说明当前我们没有正确引入对JSC的依赖,需要检查两个地方:



2.2.1. 检查依赖库

  1. 检查在主项目中gradle文件是否有添加JSC的依赖

    implementation "org.webkit:android-jsc:+"
    
  2. 检查根目录下的build.gradle文件中,是否有提供JSC依赖库检索的URL

    maven {
        // Android JSC is installed from npm
        url("$rootDir/../node_modules/jsc-android/dist")
    }
    

    这个地方需要重点检查一下URL地址是不是对的



2.2.2. 手动导入aar

还有另一种解决方案是,直接手动导入JSC的依赖库即可;因为该依赖库是没有其它依赖对象,是单独存在的,所以可以直接导入。找到JSC库的位置是在

$rootDir/../node_modules/jsc-android/dist

,一般根据RN项目是的情况,是在当前根目录的上一目录下,存在

node_modules

文件夹,再通过以下路径查找到对应的JSC库即可。

参考路径:../node_modules/jsc-android/dist/org/webkit/android-jsc/r245459(这是版本号)/android-jsc-版本.aar

将该路径下的JSC文件作为aar直接导入,可以不添加上述的依赖库引用;

注意,根据自己选择不同的JSC,是可能用到不同的JSC库的。除了

android-jsc

还有另一个是

android-jsc-intl

,这个是取决于RN项目中的配置使用了哪个。

一般和默认情况下,都是使用

android-jsc



该部分信息可以参考:https://stackoverflow.com/questions/56734877/getting-library-libjsc-so-not-found-after-upgrading-react-native-to-0-60-rc2

def useIntlJsc = false

if (useIntlJsc) {


implementation ‘org.webkit:android-jsc-intl:+’

} else {


implementation ‘org.webkit:android-jsc:+’

}

具体使用的JSC引擎依赖需要根据实际情况而定。



2.2.3. RN bundle使用额外的资源文件



3. RN项目更新

对于已打包出来的 RN 依赖库,已经添加到了相应的本地 aar 依赖及打包了相应的模块后,如果 RN 模块需要更新,需要支持 React 层的其它第三方控件使用时,需要添加相应的依赖库或更新。



3.1. 添加依赖库并更新

对于 JS 需要增加依赖或更新版本的,在

package.json

的版本管理文件中,在

dependencies

节点下更新相应的依赖库或版本。

//如更新两个新的JS依赖库
{
    "dependencies":{
        "react-native-wheel-color-picker": "^1.2.0",
        "chroma-js": "^2.4.2"
    }
}



dependencies

中添加或更新后,需要同步一下 RN 项目的依赖。

  1. 删除掉

    yarn.lock

    文件,防止项目的版本被锁定而出现问题
  2. 使用命令

    yarn

    同步项目依赖库(必要时可能需要科学上网,请根据实际情况而定)
  3. 以往正常的项目,使用

    yarn android

    尝试运行是否正常,目的是为了确认添加的 JS 依赖库被正常添加,相应的 native 依赖库也是正常依赖了能运行起应用。



版权声明:本文为u011374875原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。