external process启动失败
- RN版本: 0.80.1
- react-native-reanimated: "3.18.0"
- gradle: 8.14.1
安装react-native-reanimated之后,运行项目会提示以下错误:
- Build file '..\node_modules\react-native-reanimated\android\build.gradle': line 87: external process started 'node --print require.resolve('react-native/package.json')' See docs.gradle.org/8.14.1/user… Starting an external process 'node --print require.resolve('react-native/package.json')' during configuration time is unsupported. * Try: > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. > Get more help at help.gradle.org. BUILD FAILED in 51s.
在react-native-reanimated\android\build.gradle中发现问题出现在resolveReactNativeDirectory函数中:初步推测是REACT_NATIVE_NODE_MODULES_DIR没有被定义,返回的结果是null。
查到相关REACT_NATIVE_NODE_MODULES_DIR相关的内容,找到了以下的帖子参考:
- [Reanimated] Unable to resolve react-native location in node_modules. | Android Build Issue | Expo monorepo #5297
- Monorepo Support: Use node resolver to locate React Native package #6482
- Running External Processes 运行外部进程
问题应该是出在REACT_NATIVE_NODE_MODULES_DIR环境变量没有被正确定义,然后这个问题的issue由第二个帖子(2024年解决)的贡献者解决,也就是这个解决方案被gradle8.14.1认为是运行外部程序,被严格限制了。
我把涉及到的代码都放到下面
def safeAppExtGet(prop, fallback) {
def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
appProject?.ext?.has(prop) ? appProject.ext.get(prop) : fallback
}
def resolveReactNativeDirectory() {
//这里safeAppExtGet返回的是null
def reactNativeLocation = safeAppExtGet("REACT_NATIVE_NODE_MODULES_DIR", null)
if (reactNativeLocation != null) {
return file(reactNativeLocation)
}
// Fallback to node resolver for custom directory structures like monorepos.
//接下来会进行这段代码,但是在Gradle8.14.1中严格限制了第三方插件运行外部程序,所以这段代码就无法运行
def reactNativePackage = file(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim())
if(reactNativePackage.exists()) {
return reactNativePackage.parentFile
}
throw new GradleException(
"[Reanimated] Unable to resolve react-native location in node_modules. You should project extension property (in `app/build.gradle`) `REACT_NATIVE_NODE_MODULES_DIR` with path to react-native."
)
}
解决方案
找了好久的解决办法,尝试降级gradle版本,从8.0到8.14都试了也不行,再降级下去,有更多的乱七八糟的bug。 react-native-reanimated文档中提到3.18、3.19、4.0版本支持RN8.0,3.18、3.19都有这个问题,4.0更是有着奇怪的bug,o(╥﹏╥)o
第一种 尝试更换为官方推荐的函数
直接修改react-native-reanimated/android/build.gradle
def resolveReactNativeDirectory() {
def reactNativeLocation = safeAppExtGet("REACT_NATIVE_NODE_MODULES_DIR", null)
// def appProject = rootProject.allprojects.find { it.plugins.hasPlugin('com.android.application') }
// def a = appProject?.ext?.has("REACT_NATIVE_NODE_MODULES_DIR")
// def f = appProject.ext.get("REACT_NATIVE_NODE_MODULES_DIR")
if (reactNativeLocation != null) {
return file(reactNativeLocation)
}
// throw new GradleException(
// "*********appProject:$appProject.=====has: $a.==========get:.==========reactNativeLocation:$reactNativeLocation."
// )
// Fallback to node resolver for custom directory structures like monorepos.
// def reactNativePackage = file(["node", "--print", "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim())
// if(reactNativePackage.exists()) {
// return reactNativePackage.parentFile
// }
// throw new GradleException(
// "[Reanimated] Unable to resolve react-native location in node_modules. You should project extension property (in `app/build.gradle`) `REACT_NATIVE_NODE_MODULES_DIR` with path to react-native."
// )
//使用Gradle8.14.1文档中要求的替代写法
try {
// 使用 providers.exec 安全执行
def execResult = providers.exec {
commandLine("node", "--print", "require.resolve('react-native/package.json')")
workingDir(rootDir)
}
def path = execResult.standardOutput.asText.get().trim()
def packageFile = file(path)
if (packageFile.exists()) {
return packageFile.parentFile
}
} catch (Exception e) {
logger.error("[Reanimated] Node command failed: ${e.message}")
}
}
第二种(推荐)添加REACT_NATIVE_NODE_MODULES_DIR环境变量
修改app/build.gradle,在该文件的顶部添加代码
//file中的路径换成你自己的react-native地址
project.ext["REACT_NATIVE_NODE_MODULES_DIR"] = file("../../node_modules/react-native");
吐槽
使用react-native-reanimated的4.0版本,在gradle的8-9版本中是需要禁用缓存org.gradle.configuration-cache=false,
不然的话,控制台会提示validateWorkletsVersion找不到。
// android/gradle.properties
//编译前记得禁用缓存
org.gradle.configuration-cache=false
def validateWorkletsVersion(Project project) {
def result = project.providers.exec {
workingDir(project.projectDir.path)
commandLine("node", "./../scripts/validate-worklets-build.js")
ignoreExitValue = true
}
if (result.result.get().exitValue != 0) {
throw new GradleException(
result.standardError.getAsText().get().trim()
)
}
}
task assertWorkletsVersionTask {
doFirst {
validateWorkletsVersion(project)
}
}
崩溃,就先这样吧。