十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

React Native运行环境区分:模拟器与真机调试全指南

React Native运行环境区分:模拟器与真机调试全指南 2. 为什么你的RN项目总卡在“环境区分”这一步先说个现象。我做React Native开发这几年最常被问到的问题不是“组件怎么写”而是“我明明照着官网装的为什么npx react-native run-android之后就是跑不起来”。这个问题十有八九出在环境上而环境问题里又有八成出在“没分清React Native运行时的两层结构”上。RN项目跑起来其实是两条并行的链路一条是Metro Bundler也就是你终端里那个开发服务器默认端口8081它负责把你的JS/TS代码通过Babel转译打包供App在开发模式下实时加载另一条是Android原生应用它负责把整个应用进程拉起来然后去Metro服务器上拉取JS Bundle。理解这件事是你排查一切运行问题的前提。1.1 环境准备其实只有三件事你在真机或模拟器上跑RN项目之前需要确认三件事Node.js版本、JDK版本、Android SDK。Node.js这块RN 0.73及以上版本要求Node 180.74以后官方要求Node 20。JDK更关键RN 0.73开始强制JDK 170.74里默认的JDK版本也是17。很多老教程让你装JDK 11那是0.68以前的事了照那个装新版RN构建时gradle同步那一步就会报错错误信息五花八门本质都是Java版本不匹配。Android SDK这块Android Studio安装时默认会装最新版的SDK Platform和Build Tools但RN项目里的gradle配置可能指定了某个特定版本。你不需要手动下载所有版本只要打开Android Studio的SDK ManagerSettings - Languages Frameworks - Android SDK把“Android SDK Platform 34”和“SDK Build-Tools”对应的版本勾上装好就行。真正容易忽略的是环境变量。Windows上你需要配置ANDROID_HOME指向你的SDK安装目录比如C:\Users\你的用户名\AppData\Local\Android\Sdk然后把%ANDROID_HOME%\platform-tools加进PATH不然adb命令永远找不到。macOS和Linux则是export ANDROID_HOME$HOME/Library/Android/sdk这类写法。1.2 分清“构建失败”和“运行失败”我建议你拿到任何运行问题先问自己一句是构建失败还是运行失败构建失败的表现是终端卡在gradle任务里最后抛出一堆报错比如Could not find com.android.tools.build:gradle:8.0.0、Failed to install the app、Execution failed for task :app:compileDebugJavaWithJavac这些。这类问题发生在“原生应用还没被装到设备上”的阶段你查的方向应该是gradle版本、SDK版本、依赖仓库地址、Java版本。运行失败的表现是App已经装到真机或模拟器上了但打开之后红屏或者白屏报Unable to load script、Connection refused、Network request failed这些。这类问题发生在“原生应用起来了但拉不到JS Bundle”的阶段你查的方向应该是Metro是否在跑、端口是否通、adb反向代理是否生效。很多新手把这两类混在一起查结果越查越乱。后文我会按这两条线分别展开。3. 模拟器路线AVD与第三方模拟器的选型与跑通模拟器跑RN是最省事的一条路但不是随便装个模拟器就能跑通的。这里面的坑集中在AVD的CPU架构和第三方模拟器的adb连接上。2.1 AVD创建注意CPU架构与系统镜像如果是用Android Studio自带的AVDAndroid Virtual Device创建时最好选择x86_64架构的系统镜像。原因很简单你的电脑是x86_64的CPU模拟器跑x86_64的镜像可以直接用硬件加速速度飞快如果选了arm64-v8a的镜像比如为了模拟新出的手机配置在Intel/AMD电脑上会走模拟翻译慢到让你怀疑人生。创建AVD时还有一个特别容易被忽略的选项Store a snapshot for faster startup勾选之后模拟器冷启动速度会快很多。另外模拟器的内存建议给到2GB以上不然打包好的App在模拟器里很容易因为内存不足被系统杀掉表现为App闪退或者回到桌面。系统镜像的API级别怎么选我用下来的经验是选你项目里compileSdkVersion对应的API级别就行或者稍微高一级也没问题。不用一味追新。比如RN 0.74默认compileSdkVersion是34那就装API 34的镜像。装镜像这一步在国内网络环境下很可能卡住如果一直下载不动可以考虑给Android Studio配置代理或者换个时间段再试。AVD环境变量确认无误后启动模拟器然后在项目根目录执行npx react-native run-android。RN CLI会自动检测到已连接的模拟器通过adb devices自动安装Debug包然后拉起App。2.2 第三方模拟器的adb识别与端口处理百度热搜词里出现了一堆“雷电模拟器”“MuMu模拟器”“夜神模拟器”确实很多人习惯用这些国内厂商的模拟器来做RN开发。这些模拟器本质上是Android虚拟机但它们的adb设备识别方式和AVD不一样——AVD启动时Android Studio会自动注册设备到adb第三方模拟器则需要你手动adb connect。比如雷电模拟器默认监听端口是5555MuMu模拟器是7555夜神模拟器是62001。连接命令是adb connect 127.0.0.1:5555连接成功后再执行adb devices你应该能看到一条127.0.0.1:5555 device的记录。看到之后再执行npx react-native run-android就能装到模拟器上。这里有个我踩过的坑不同版本的雷电模拟器默认端口不一定一样。如果adb connect 127.0.0.1:5555提示连接失败别猜直接打开模拟器的安装目录看看有没有一个adb.exe或者其他adb工具先用模拟器自带的adb连接再切换到你系统PATH里的adb。或者干脆看模拟器设置里的“ADB调试端口”很多版本都直接显示出来了。还有一点第三方模拟器默认的CPU架构大多是x86_64所以跑RN完全没问题。但如果你看到模拟器里安装APK时一直卡在“正在安装”或者提示“app not installed”多半是模拟器的Android版本太老跟你的minSdkVersion不匹配或者模拟器自身的adb服务出了问题重启模拟器就好。4. 真机调试链路USB识别、设备授权与adb reverse那点事真机调试才是真正的分水岭。模拟器跑通不算什么真机能跑通才算入门。真机调试流程比模拟器多出几个关键环节进入开发者模式、开启USB调试、装驱动、adb授权、端口反向转发。每一步都有各自的坑。3.1 打开开发者选项和USB调试的正确顺序首先你要在手机上开启开发者选项。这个操作在不同厂商的定制系统里位置不太一样但原理相同打开“设置”找到“关于手机”找到“版本号”连点7次系统会提示“您已进入开发者模式”。小米还有个额外的限制需要登录小米账号才能开启USB调试。华为的部分机型需要插入SIM卡后才能打开“开发者选项”里的“USB调试”。这些细节教程里一般不写但实际开发中确实遇到过。进入开发者选项后找到并打开三个开关USB调试、USB安装有的手机叫“USB安装应用”或“允许通过USB安装应用”、USB调试安全设置有的手机叫“允许通过USB模拟点击”。其中USB调试是必须的USB安装如果是首次装Debug包也建议开否则run-android安装APK时会被系统拦截。3.2 为什么命令输入了还是404adb reverse的完整链路用数据线把手机连上电脑后手机上会弹出“是否允许USB调试”的对话框勾选“始终允许来自此计算机的调试”然后点允许。接着在终端里执行adb devices如果列表里显示device状态说明设备识别成功了。我见过好多人在这一步卡住排查思路如下先adb kill-server再adb start-server重启adb服务换一根数据线——现在很多type-C线只能充电不能传数据这是最容易被忽视的一点把USB连接模式从“仅充电”切换成“文件传输/MTP”部分手机在仅充电模式下会禁用ADB在Windows设备管理器里看有没有识别出ADB Interface设备如果显示黄色感叹号去装OEM USB驱动Google USB Driver可以解决大多数问题手机端如果弹过授权框但你点了“取消”可以在开发者选项里找到“撤销USB调试授权”然后重新插拔。设备识别搞定之后很多人执行npx react-native run-android却发现App装好后一打开就是红屏报错提示Unable to load script from assets index.android.bundle或者Connection refused。这是因为你的手机通过USB连接网络跟电脑不互通App里的localhost:8081指向的是手机自己而不是你的电脑。解决办法就是执行adb reverse tcp:8081 tcp:8081它的作用是把手机的8081端口转发到电脑的8081端口这样App里的localhost:8081请求就会通过USB数据线直接打到电脑上的Metro服务器。执行完这条命令后在手机App里摇一摇或者执行adb shell input keyevent 82打开Developer Menu点“Reload”就能正常加载JS Bundle了。3.3 无线调试Android 11以上的另一种选择如果你不想每次都用数据线Android 11及以上版本提供了无线调试功能。在开发者选项里打开“无线调试”点“使用配对码配对设备”屏幕上会显示IP地址、端口和配对码。电脑端执行adb pair 192.168.x.x:PORT按提示输入配对码配对成功后执行adb connect 192.168.x.x:PORT这时候adb devices里就会多出一个无线连接的设备。需要注意无线调试要求手机和电脑处于同一个网络公司里那种隔离了AP客户端互访的网络不行。另外只要数据线一插上adb就会优先走USB通道把无线连接踢掉这个是正常现象。无线调试还有一个好处配合adb reverse同样有效所以在无线状态下执行一次adb reverse tcp:8081 tcp:8081也能正常热更新。我个人在实际开发中更喜欢无线方式省得数据线晃来晃去挡着键盘。5. 真机调试状态下的Metro Bundler与高频报错实践很多人在模拟器上能跑通一到真机上就报“上传失败:网络请求错误”其实问题不一定出在手机而在于你对Metro Bundler的运行机制不够了解。这一节详细聊聊Metro是怎么工作的以及真机调试时最常撞上的几个报错的完整排查链路。4.1 Metro Bundler原理简说Metro是React Native官方的打包器它的工作流程可以简化成三步从入口文件通常是index.js开始沿着import/require关系把所有JS/TS和静态资源文件解析出来通过Babel做语法转译和兼容处理最后按平台Android/iOS分别打包成一个或多个Bundle文件通过HTTP服务供App拉取。Debug模式下App不会把整个Bundle打进安装包里而是启动时向Metro服务器请求Bundle。所以你在开发时改代码只要Metro还在跑App里就能实时热更新这就是“热重载”和“Fast Refresh”的底层逻辑。但这也意味着Debug包对开发服务器有强依赖。如果Metro挂了、端口不通、网络被代理挡了App就加载不出来。4.2 高频报错一上传失败: 网络请求错误这个报错原文是类似error: 上传失败: 网络请求错误, ([object object]) tunneling socket could not be established或者Caused by: java.net.ConnectException: Failed to connect to localhost/127.0.0.1:8081。看到这个报错首先要排查的是代理。tunneling socket could not be established这个错误非常典型它说明你的终端或者Node进程配置了HTTP代理而代理服务器无法帮Metro完成到localhost:8081的连接——因为localhost本身就不应该走代理。这种情况在公司电脑上尤其常见你大概率设置了全局系统代理。解决办法分三个层面终端里临时关掉代理环境变量unset http_proxy https_proxyWindows的PowerShell用Remove-Item Env:http_proxy -ErrorAction SilentlyContinue Remove-Item Env:https_proxy -ErrorAction SilentlyContinue检查gradle.properties里是否配置了代理systemProp.http.proxyHost... systemProp.http.proxyPort...如果配了注释掉再试。在Metro启动时显式禁用代理环境变量NO_PROXYlocalhost,127.0.0.1 npx react-native start排除了代理问题后再排查8081端口是否被其他程序占用。macOS/Linux用lsof -i :8081Windows用netstat -ano | findstr :8081如果端口被占用要么杀掉占用进程要么给Metro换一个端口npx react-native start --port8088然后别忘了把adb reverse tcp:8088 tcp:8088也一起改掉。4.3 高频报错二Unable to load scriptUnable to load script from assets index.android.bundle这个红屏是老朋友了。出现这个问题的原因通常是Metro没有启动或者App启动时找不到Bundle文件。实践中最容易踩的坑是你执行了npx react-native run-android但忘记另开一个终端启动Metro。新版本的RN CLI其实会在run-android时自动拉起Metro但如果你之前手动启动过Metro又挂掉了或者Metro端口被占用导致自动启动失败App启动时就拿不到Bundle。还有一个值得注意的情况如果你的项目是从老版本RN迁移过来的有时候android/app/src/main/assets/index.android.bundle这个文件是空的或者缺失的Release包里会白屏Debug包则报“Unable to load script”。处理办法是npx react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res这条命令会把Bundle打到assets目录里Release包才能离线加载。但如果是Debug调试我还是建议把assets目录里的Bundle删掉否则Metro热更新会失效——因为App会优先读取打包在安装包里的Bundle。4.4 几个容易忽略的Release包细节热搜词里有“ReactNative如何在真机/模拟器上运行”这样的大白话说明很多人还在用Debug包调试。Debug包和Release包有本质区别Debug包体积更大、包含开发服务器地址和日志输出、每次启动都要连MetroRelease包体积小、运行快、但默认关闭了开发者菜单也没有热更新。如果你需要给测试人员一个可以独立安装的包用npx react-native run-android --moderelease它会走gradle的assembleRelease任务自动生成带签名的APK。但要注意Release包默认使用release签名文件如果项目里没配置签名会使用Android Studio生成的默认debug.keystore签名可以安装但无法上架。Release包里如果没有预置Bundle就是我上面说的assets/index.android.bundle安装后打开会白屏或者报“Unable to load script from assets”。Release包如果没在android/app/build.gradle里配置applicationId对应的签名测试机和真机上之前装过同包名的Debug包可能因为签名不一致需要先卸载旧包再安装。6. 从热门搜索词看新手高频踩坑整理一份排查顺序其实每个人报出来的问题都不太一样但细细看下来范围也就那么几个。这一节我把搜索词里那些看起来很吓人的报错翻译成人话做一个对照表然后给你一份可以照抄的排查顺序。5.1 那些看起来吓人的报错到底是什么意思我整理了一张表基本覆盖了真机/模拟器运行RN时最常遇到的几类报错以及对应的处理方向现象/报错本质原因首查方向adb devices列表为空驱动没装好、USB模式不对、数据线不支持传输换线、切MTP模式、装OEM驱动adb devices显示unauthorized手机上没授权USB调试拔线重插弹窗时勾选始终允许Failed to connect to localhost/127.0.0.1:8081App连不上Metro确认Metro在跑、确认adb reverse生效upload failed: 网络请求错误 ([object object])打包上传时网络层被代理拦截关代理、重置环境变量、重启Metrotunneling socket could not be establishedHTTP代理无法连接localhost取消系统代理NO_PROXY配置Could not find com.android.tools.build:gradle:X.X.Xgradle依赖仓库拉不到检查仓库镜像、检查网络、检查gradle版本Unable to load script from assetsDebug包缺少Metro连接或Release包缺少预置Bundle启动Metro或bundle到assetsExecution failed for task :app:compileDebugJavaWithJavacJava版本与gradle要求不匹配检查JDK版本是否17App安装后在模拟器里闪退模拟器内存不足或日志里MediaCodec/so库问题加大模拟器内存换x86_64镜像真机打开App一直白屏Metro服务器没启动或端口被防火墙拦启动Metro、关闭防火墙、确认adb reverse搜索词里还有一类怪东西比如content://com.baidu.searchbox.fileprovider/...、file:///storage/emulated/0/android/data/com.baidu...这类路径。很多新手在日志里看到这种路径一头雾水其实这是Android系统在7.0以后引入的FileProvider机制产生的URI用来在App之间安全地共享文件。它跟React Native本身没有直接关系通常出现在你手机上的某个App比如百度、微信、QQ在尝试通过FileProvider读取文件时。RN项目里如果你用到图片选择、文件上传之类的库也可能看到类似格式的URI但那是正常现象不需要害怕。另外搜索词里出现了unable to find suitable visual studio toolc这种报错我一眼认出这是VS Code在编译Flutter插件时找不到C工具链的问题而不是React Native的报错。如果是做RN你不需要装Visual Studio的C工具链。这类报错提醒我们遇到报错先看清报错属于哪个技术栈别拿别人的药方往自己身上用。5.2 我建议的排查顺序先简单后复杂真机/模拟器跑RN项目如果遇到问题我建议按这个顺序排查比瞎猜高效得多第一步确认基础环境。运行node -v、java -version确认Node和JDK版本满足当前RN版本要求。不满足就先去解决版本问题。第二步确认设备连接。运行adb devices看设备是否在线。这一步是整个链路的基础设备都没有后面所有的报错都会让人怀疑人生。第三步确认Metro状态。看终端窗口里Metro是否正常输出日志刷新日志是否有Bundling记录。如果Metro没跑先启动它如果端口被占用换端口并修改adb reverse。第四步确认端口反向代理。真机调试执行一次adb reverse tcp:8081 tcp:8081然后重新Load。模拟器如果用的是AVD一般RN CLI会自动做这事第三方模拟器如果连不上先确认adb connect状态。第五步排除代理干扰。还是报网络错误时临时取消系统代理和Node环境变量里的代理用最干净的直连状态再试一次。第六步清理缓存。执行npx react-native start --reset-cache重跑Metro或者进android目录执行./gradlew clean清理构建缓存。第七步看完整日志。不要只看终端里最后一行红字要往上翻找到Caused by:或者at com.facebook.react...这些定位异常发生位置的堆栈信息再精准搜索。很多时候报错信息里已经告诉你是哪个文件哪行代码出的问题只是被淹没在日志海洋里了。5.3 关于“真机预览图片不显示”这类奇怪问题热搜词里有一条“什么真机预览的时候图片都不显示这是为什么在开发者工具上就正常显示”。看到这个我挺感慨的因为这类问题在RN里太典型了。开发者工具里能显示真机上不显示多半是因为图片资源走的是开发服务器地址而真机访问不到开发服务器。比如你在代码里写require(../assets/logo.png)Metro会把它作为静态资源地址映射到localhost:8081/assets/...。在电脑上的开发工具里这个地址当然能访问但在真机上如果你没有做adb reverse或者项目配置了baseURL指向一个局域网IP而你的手机访问不了这个IP图片自然就加载不出来。解决办法除了确保adb reverse生效之外还有一种更稳的方式把图片从require改为从远程CDN加载或者把图片放在android/app/src/main/res/drawable/目录下用原生资源方式引用。但原生资源方式要处理不同density的适配drawable-mdpi/hdpi/xhdpi/xxhdpi比较麻烦。所以我的建议是本地资源优先走Metro的require如果出现真机加载不了的问题先解决网络链路而不是改代码。7. 写在最后我的习惯与建议复盘一下真机/模拟器跑RN项目的核心其实就是两条链路构建链路gradle、JDK、SDK、依赖仓库和运行链路Metro、adb、端口转发。排查问题时第一件事永远是确认你现在卡在哪条链路上而不是一上来就清缓存、重装依赖。我自己现在的习惯是这样的新项目第一次跑通之前先手动启动Metronpx react-native start另开一个终端跑adb devices确认设备在线然后再执行npx react-native run-android。全程关注日志输出Metro窗口出现Bundling和Running 应用名字样才算真正跑通。排除问题同理一次只动一个变量要么关代理要么改端口不要同时做两三件事不然出了问题你根本不知道是哪个步骤导致的。最后分享一个小技巧真机调试时如果出现连不上Metro的问题别急着重启电脑。先运行adb kill-server adb start-server然后重新插拔数据线最后执行adb reverse tcp:8081 tcp:8081。这一套组合拳能解决我遇到的大约七成概率的“莫名其妙连不上”问题。剩下的三成多半是代理或者Metro进程僵尸化清掉重来就好。React Native开发的体验调试链路占了一半的功劳。把底层这些机制理清楚后面不管是加第三方库、做原生模块、还是上架打包都会顺很多。希望你在真机和模拟器上都跑出自己的第一个“Hello World”那种感觉比在文档里看一百遍都强。
返回列表