更新说明
日期 | 更新内容 |
---|
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 是可以正常编译和安装程序的。所以这里可以很明确这个问题并不是真的问题。
解决方案: 以下是查询到网络上的一些说明,作为参考提供:
- github issue: https://github.com/react-native-community/cli/issues/1226
- 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.
- 基于macOs环境,退出当前所有的android项目,确保整个AS的进程完全退出(注意不要只退出当前的项目,是所有的AS项目都需要退出,整个进程需要关闭)
- 重新启动相关项目,重新编译即可
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文件,调整运行的应用模块
解决方案:
- 打开gradle文件:
xxx/node_modules/react-native-reanimated/android/build.gradle - 修改以下的
:app 模块名称为需要运行的实际应用模块名称
def engine = "jsc"
if (project(':app').ext.react.enableHermes) {
engine = "hermes"
}
1.3. 模块中未配置enableHermes 的字段
RN会根据配置信息自行使用JSC或者是Hermes的JS引擎,但是默认的RN项目实际上都是使用的JSC的引擎。在RN的官网中有提及需要在项目中配置上enableHermes 的字段
project.ext.react = [
enableHermes: false,
]
很明显这里就是使用了JSC的引擎,而且不人为强制修改是不会变的。但是在node_modules 中的JS引擎项目中,有使用了这个参数信息进行判断。当不存在这个字段时,就会报错。
def engine = "jsc"
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"
}
}
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"]
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 {
url("$rootDir/../node_modules/react-native/android")
}
maven {
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. 检查依赖库
-
检查在主项目中gradle文件是否有添加JSC的依赖 implementation "org.webkit:android-jsc:+"
-
检查根目录下的build.gradle文件中,是否有提供JSC依赖库检索的URL maven {
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引擎依赖需要根据实际情况而定。
|