开局一张表,环境全靠配
写这篇复盘的时候,我盯着终端里那一连串红字发呆。很多人以为搭个 React Native 环境就是跑个 CLI,然后一路回车躺平。实际上它更像在拼一层看不见的积木:JDK → Gradle 本体 → 插件/依赖镜像 → NDK → 真机/模拟器。前面没拧紧螺丝,后面直接给你抛个异常让你怀疑人生。
今天不整虚的,直接把我在 Windows 上跑通 HelloRN 项目的完整排错时间线摊开。每解决一个环,下一个隐藏问题才会像剥洋葱一样露出来。如果你也在为 Android 环境发愁,这篇应该能帮你省下至少半天的调试时间。
连环扣式报错:我的排错时间线
整个过程基本是按"发现报错→找原因→试办法→暴露新问题"的节奏走的。我把那十几轮的折腾按顺序理了一下,你看看有没有熟悉的影子:
- 第一轮:
java -version找不到。 别笑,这确实是第一步。系统要么没装 JDK,要么环境变量JAVA_HOME和Path根本没配对。我直接用了winget install EclipseAdoptium.Temurin.17.JDK装了一套干净利落的 JDK 17。 - 第二轮:
JAVA_HOME is not set。 配了路径但gradlew.bat还是读不到 java。这里有个细节:JAVA_HOME必须指向根目录,不能带引号,也不能有尾斜杠。Path里记得补%JAVA_HOME%\bin。 - 第三轮:
No emulators found+exit code 9009。 模拟器没开其实不致命,真正要命的是那个 9009 错误码。它本质上是 Windows 报"命令找不到",说明 Gradle 启动进程压根没拿到正确的 JDK 上下文。这时候硬调系统变量很容易翻车,最稳的做法是直接在android/gradle.properties里写死:org.gradle.java.home=C:/.../jdk-17...(注意用正斜杠),彻底绕过系统环境变量继承的坑。 - 第四轮:只开了模拟器,应用没进去。 卡在中间环节了,通常是 APK 没成功安装。这时候别瞎猜,直接用
adb devices看设备在线没,pm list packages查包名,logcat抓日志,三段定位一下就知道是签名问题还是构建中断。 - 第五~八轮:Gradle 下载慢与镜像配置翻车。
Downloading gradle-9.4.1-bin.zip卡住半天,或者INITIALIZING [2m] 0%动不了。国内直连services.gradle.org经常僵死。网上很多教程给的腾讯/华为镜像地址看着挺像,但模型经常笔误漏掉域名部分,导致握手失败。正确做法是去gradle-wrapper.properties换 wrapper 镜像,然后在settings.gradle的pluginManagement和dependencyResolutionManagement里插入口阿里云镜像,并且一定要放在最前面 ,google()和mavenCentral()留着兜底就行。 - 第九~十轮:NDK 缺失与 Connection refused。 RN 0.87 的新架构强制要求 NDK 28.2.13676358。你以为装上就行了?结果直接报
Connection refused。这是因为 SDK Manager 在国内网络下经常被拒,你以为下载成功了,其实目录里是个空壳。最终只能老老实实用清华镜像手动拉android-ndk-r28b-windows.zip,解压后重命名放到...AndroidSdk\ndk\28.2.13676358,靠source.properties里的Pkg.Revision校验版本,再gradlew --stop重新编译。
核心卡点:到底卡在哪儿了?
把上面那些碎片化的报错拎出来看,其实就四座大山。跨过去,环境就顺了。
1. JDK 是地基,别信环境变量
前几轮反复失败,根源都在 Gradle 认不出 JDK。很多人配完 JAVA_HOME 就去跑脚本,结果子进程根本拿不到新值。Windows 的环境变量是按父进程逐层继承的,你改了注册表或系统设置,VS Code、终端、甚至 npm 都得彻底退出重开才生效。与其跟继承机制较劲,不如在项目级 android/gradle.properties 里用 org.gradle.java.home 锁定路径,一劳永逸。
2. Gradle 慢不是死机,是网络在作祟
Downloading 卡住或者 INITIALIZING 0%,90% 都是请求发出去但被墙了。判断是"慢"还是"死",别看等待时长,去临时缓存目录看 .part 文件的大小有没有在涨。解决思路很明确:wrapper 换镜像,settings.gradle 两组 repositories 把国内源置顶,保留官方源防崩。如果是公司内网,记得在 gradle.properties 里补上 systemProp.http(s).proxyHost 和端口。
3. NDK 是个"哑巴"坑
RN 新版架构对 C++ 工具链要求很死。装了 NDK 还报错 Connection refused,通常是因为 SDK Manager 的下载通道本身就被拦截了,你看到的"已安装"全是假的。手动下载对应版本的 zip,按标准目录结构摆放,并用 source.properties 核对版本号。记住一点:NDK 校验靠版本号,不靠文件夹名字。 同时检查 local.properties 里的 sdk.dir,必须指向同一个 SDK 根目录。
4. 代理的二义性
Connection refused 不等于超时,它意味着端口被直接拒绝。很多时候是 gradle.properties 里写了 127.0.0.1:7890,但代理软件根本没起,或者起了在别的端口。要么把代理开对,要么干脆把 proxy 四行注释掉。另外提醒一句:sdkmanager 命令行和图形化界面根本不读 gradle.properties 的代理配置,得单独给它们配,否则永远在原地打转。
沉淀下来的通用经验
折腾一圈下来,总结了几条以后不管搭什么环境都能直接抄作业的准则:
- 读懂错误码的潜台词 :Windows 报
9009= 命令找不到;Connection refused= 端口不通(大概率代理残留)。别把警告当错误看,比如No emulators found只是提示,真正致命的永远是紧跟其后的FAIL。 - 镜像配置的三原则:新镜像放最前抢流量,原始源保留兜底防失联,文件名和哈希值千万别手贱改,Checksum 不对 Gradle 直接熔断。
- 区分"慢"与"死":观察缓存目录体积变化比干瞪眼管用得多。
- 环境变量不是点了保存就生效:只要是你正在运行的 IDE 或终端,改完必须重启。这是操作系统的基本法则,别指望热更新。
接下来怎么办?
目前这条依赖链已经基本打通到了 NDK 这一环,离 BUILD SUCCESSFUL 就差临门一脚。剩下的动作很明确:
- 理顺网络:把代理开关对齐,或者把
gradle.properties里的 proxy 配置删干净,消灭Connection refused。 - 手动就位 NDK:用国内镜像拉取
28.2.13676358版本,按规范路径解压,跑一次gradlew --stop清理旧缓存。 - 重新执行构建指令。看到终端输出
Installed on 1 device,恭喜你,HelloRN 的世界终于向你打开了。
环境搭建从来不是玄学,而是逻辑推演。每一步报错都在告诉你缺了哪块拼图。希望这篇流水账式的排错记录,能让你下次面对红色报错时少皱几下眉头。咱们下期工程实践见。