react-native-reanimated 关于运行外部程序相关的问题

191 阅读2分钟

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。 wechat_2025-08-04_205716_755.png 查到相关REACT_NATIVE_NODE_MODULES_DIR相关的内容,找到了以下的帖子参考:

问题应该是出在REACT_NATIVE_NODE_MODULES_DIR环境变量没有被正确定义,然后这个问题的issue由第二个帖子(2024年解决)的贡献者解决,也就是这个解决方案被gradle8.14.1认为是运行外部程序,被严格限制了。 wechat_2025-08-04_210135_026.png 我把涉及到的代码都放到下面

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

崩溃,就先这样吧。