
1. 为什么我建议在模拟器上跑 Expo先说清楚原理和选型我先从一个很常见的场景说起。你刚用npx create-expo-app建好一个项目运行npx expo start终端里跳出一个二维码和一堆提示你下意识掏出手机扫了一下然后发现手机和电脑不在同一个局域网二维码扫了个寂寞。很多人卡在这一步就放弃了但换个思路用安卓模拟器跑 Expo 其实更省事而且它本来就是开发者日常最顺手的调试环境之一。在很多团队里安卓模拟器是跑 Expo 项目的第一站而不是真机。原因很简单模拟器就在你电脑上不依赖局域网不会因为手机息屏、锁屏、切网断开调试连接还能随时截图、录屏、快速切换屏幕尺寸。这篇文章我不会只讲按哪个键就能跑而是会把 Expo 和安卓模拟器之间那层关系拆开讲清楚——它们是怎么连上的、三种运行方式有什么区别、我在实际调试中踩过的坑怎么避开内容偏向实操适合刚接触 React Native 的开发者也适合被各种启动报错折腾到怀疑人生的朋友。1.1 Expo 与安卓模拟器这对组合解决什么问题先说清楚一件事Expo 本身并不是一个独立的编程语言它是 React Native 之上的一套开发工具和运行时环境。你的项目代码最终要跑起来需要有两样东西——一个是 Metro 打包器它在你的电脑上启动默认监听 8081 端口把 JS 代码实时编译成一个 bundle另一个是客户端容器它可以是一个安装包安卓上叫 APK负责把 bundle 加载进去渲染成真实界面。安卓模拟器在这里扮演的角色就是客户端容器的宿主。模拟器里可以安装 Expo Go——这是 Expo 官方提供的调试客户端也可以安装你自己打包的 dev client也就是 Development Build。它们在模拟器里启动之后会主动去连接电脑上 Metro 的 8081 端口拉取 JS bundle然后执行并渲染。这里藏着一个很多新手不理解的问题模拟器里的电脑地址不是localhost而是10.0.2.2。因为模拟器本身是一台独立的虚拟机localhost指向的是模拟器自己。不过你不需要手动去改地址Expo CLI 会自动通过adb reverse把模拟器的 8081 端口反向映射到电脑本机所以在绝大多数情况下你只要在启动 Expo 服务之后按一个键它就能自己跑起来。一旦你理解了这层连接关系后面遇到白屏、连不上、卡加载这些问题时排查思路就会清晰很多。1.2 先认清两条路Managed 工作流与 Development Build很多人习惯把用 Expo 开发等同于用 Expo Go 开发其实这是两码事。Expo 生态里现在主要有两条路线选哪条决定了你在模拟器上的启动方式完全不同。第一条是 Managed 工作流也就是传统的 Expo 托管工作流。你只写 JS/TypeScript所有原生模块都由 Expo 帮你集成在 Expo Go 这个 App 里面。想用什么功能就通过npx expo install安装对应的 Expo SDK 库不需要碰 Android 原生工程。这种模式在模拟器上跑起来非常轻因为你不需要先编译一个 APK直接装好 Expo Go 就行。第二条是 Development Build中文一般叫开发构建。当你用到了需要自定义原生代码的库比如某些支付 SDK、地图、推送服务或者需要修改 Android 工程里的配置文件时Expo Go 就不够用了你得用npx expo run:android生成原生项目并编译出自己的调试版 APK。这个 APK 集成了 expo-dev-client它在模拟器里启动后同样连回 Metro 加载 JS。我把两条路径的差异整理成一个表格你对照自己的项目实际情况做选择。对比项Managed Expo GoDevelopment Build是否需要编译 APK不需要装官方 Expo Go 即可需要首次运行会执行 Gradle 编译支持纯 JS/TS 开发完全支持支持支持自定义原生代码不支持支持冷启动速度快秒开编译一次之后也很快适合阶段原型、Demo、纯逻辑调试接近上线的正式迭代、接原生 SDK新增原生依赖时直接安装 Expo SDK 版本即可需要重新编译开发构建我见过不少开发者项目已经用到自定义原生模块了还继续用 Expo Go 调试结果每次启动都黑屏代码明明没报错却看不到界面。其实这不是项目坏了而是客户端容器不认识你的原生模块。搞清楚地用哪条路调试方向才不会错。2. 环境搭建一个能跑起来的安卓模拟器要准备什么在跑 Expo 之前你得先有一个能正常启动的安卓模拟器。很多人一上来就装一堆工具结果系统镜像下载不下来或者模拟器启动黑屏然后以为是自己电脑不行。其实多数环境问题出在版本选型和一些容易被忽略的细节上。2.1 软件清单与版本选择先说必备的软件。跑 Expo 安卓模拟器最小组合是四样Node.js建议 LTS 版本、Android Studio、Android SDK 里的命令行工具和模拟器组件还有 Java 运行时。Java 不是给 Expo 用的而是给 Gradle 用的编译原生模块和开发构建时需要它即便你只跑 Expo Go装齐了也能少踩点坑。安装 Android Studio 的时候需要注意一个细节完整安装会把 SDK Manager、AVD Manager、模拟器组件一并装好但如果你只装了命令行版本后续还得手动用sdkmanager补装platform-tools、emulator、system-images这些组件容易漏。一般推荐直接用 Android Studio 的官方安装包它会帮你把默认组件配好。关于版本匹配我的建议很直接Node 用当前 LTSAndroid Studio 用稳定版Java 用 Android Studio 要求的版本目前主流是 Java 17。不要追求新到 beta 版也不要停在特别老的版本。Expo SDK 有自己对应的 React Native 版本而 React Native 又对 JDK 版本有要求所以旧版本 JDK 往往会在编译阶段报一些语义不明的错。装完之后打开 Android Studio进入 SDK Manager确认下面这几个包存在Android SDK Platform-ToolsAndroid EmulatorAndroid SDK Build-Tools至少一个系统镜像System Image如果你之前只装了部分组件可以在这里一次性补全。这一步做完你的环境就完成了一大半。2.2 创建虚拟设备时容易忽略的几个参数打开 AVD Manager 创建虚拟设备时很多人会选择默认的 Pixel 设备再加一个 Google APIs 镜像然后直接下一步。这个流程没错但有几个参数值得多看一眼它们直接影响 Expo 在模拟器里的体验。第一是系统镜像的 CPU 架构。如果你的电脑是 Intel 或 AMD 处理器建议选 x86_64 版本的镜像因为这个架构在模拟器上支持硬件虚拟化运行速度快发热也少。如果你的电脑是 Apple SiliconM 系列芯片那就选 ARM64 的镜像跑起来效率更高。选错架构不是不能跑而是会慢到让你放弃调试。第二是 Google APIs 版本和 Google Play 版本的区别。Google Play 镜像里预装了 Play Store 和相关服务体积更大也带了 Google 登录等依赖Google APIs 镜像则是纯开发环境没有商店。对日常开发来说两者都行但如果你要调试登录、推送、地图这类依赖 Google 服务的功能选 Google Play 镜像会更接近真机环境。第三是内存和存储。不要给模拟器分配太高的 RAM比如你的电脑只有 16GB给模拟器 4GB 就差不多了预留内存给 Metro 打包器、Android Studio 和浏览器否则整机卡顿反而拖慢调试速度。内部存储建议给到 8GB 以上Expo Go 或开发构建装完之后还要缓存一些依赖。第四是 GPU 渲染模式。创建完设备之后可以在 AVD 的配置里把 Graphics 设置为 Hardware也就是宿主的 GPU 参与渲染。这一步能让模拟器里的界面渲染更流畅尤其是 Expo 项目里动画、渐变这类界面元素比较多的时候效果很明显。我第一次跑 Expo 项目时就是因为在公司电脑上选了一个 ARM 镜像导致界面加载巨慢按一次刷新要等十几秒后来换到 x86_64 镜像整体体验像换了一台电脑。所以创建 AVD 时别贪快把架构和 GPU 这两项调好后面省下的时间远多于这会儿多看的五分钟。3. 把 Expo 应用跑进模拟器三种启动方式和完整实操环境准备好了模拟器也能启动了接下来就是把 Expo 项目接进去的那一刻。这一步看着简单实际上有几种不同的操作路径你按一下a、按shift a、扫码和在模拟器里手动输入地址背后对应的原理都不一样。我把它们拆开讲清楚。3.1 方式一Expo Go expo start 一键启动最省心这是最常规的一条路适合所有纯 JS/TS 项目也是我日常使用频率最高的方式。具体操作分三步第一步启动模拟器。你可以直接在 Android Studio 里选中一个 AVD 点启动按钮等模拟器完全进入桌面。第二步在项目根目录运行npx expo start正常情况下终端里会显示 Metro 的启动信息和一个二维码。这时候你直接按键盘上的aExpo CLI 会自动检测当前运行的安卓设备通过 adb 安装 Expo Go如果模拟器里没有装然后自动打开项目。这里有个细节值得注意Expo CLI 之所以能自动打开模拟器里的应用靠的是 adb。如果你电脑上同时连着真机和开着模拟器按a时可能会选错目标。终端里会提示你选择连接的设备你不确定的话就先用adb devices看一下设备列表确认模拟器的设备编号。第三步如果一切顺利模拟器屏幕里会出现加载动画几秒后进入你的应用界面。每次改代码保存之后 Metro 会自动热更新连按刷新都不用。这套流程之所以省心核心原因是 adb reverse 自动化。Expo CLI 在你按a的时候会偷偷执行一条 adb 反向端口转发命令把模拟器里的 8081 端口映射到电脑本机。这样模拟器里的 Expo Go 访问localhost:8081实际上访问的就是你电脑上的 Metro。如果哪天按a之后界面卡在加载页不动十有八九是这条反向转发失效了手动跑一下就能救回来adb reverse tcp:8081 tcp:80813.2 方式二Development Build 跑原生代码能碰原生工程如果你的项目需要用自定义原生模块或者要改 AndroidManifest 之类的原生配置那就不能靠 Expo Go 了得走 Development Build 这条路。第一步确认项目里装了 expo-dev-clientnpx expo install expo-dev-client第二步运行npx expo run:android这个命令会做三件事生成android原生工程目录、用 Gradle 编译出 debug APK、自动安装到已启动的模拟器上。首次执行的时间取决于你的网络和电脑性能快的时候两三分钟慢的时候可能十几分钟主要卡在 Gradle 下载依赖这一步。这个过程我建议你盯着终端看出现BUILD SUCCESSFUL字样才算完。第三步之后日常调试还是用npx expo start启动 Metro但注意这时候不能再按a了因为a默认打开的是 Expo Go。你需要按shift aExpo CLI 才会去找已安装的 Development Build 来打开项目。如果你不想用快捷键也可以直接在模拟器桌面上点击你的应用图标它启动后会自动尝试连接 Metro扫码也行二维码扫进 dev client 一样能加载项目。run:android之后你的android目录会被创建并纳入 Git 管理这意味着你已经从 Managed 工作流切到了开发构建的模式。后面每新增一个原生依赖都需要重新执行一次run:android重新编译这也是开发构建模式里最花时间的一步。3.3 方式三手动输入地址和清空缓存启动救急用上面两种方式是标准流程但实际操作中总有不按套路出牌的时候。比如 Metro 正常启动模拟器里 Expo Go 也装好了但你按a或者shift a都没反应界面一直停在 Expo Go 的主页。这时候最直接的办法就是手动打开项目。方式也很简单在模拟器里打开 Expo Go点界面上的Enter URL manually输入地址手动连接然后输入exp://10.0.2.2:8081为什么是10.0.2.2前面说过模拟器里的宿主机地址就是10.0.2.2exp://是 Expo 专用的协议头8081 是 Metro 的端口。这个输入动作会跳过 Expo CLI 的自动化设备选择逻辑直接建立连接所以经常被用来排查CLI 能启动但设备连不上的问题。另外补充一个清缓存启动的用法。因为 Metro 的缓存机制偶尔会造成改了代码但界面不更新的假象或者某些模块报奇怪的解析错误。这时候直接重启 Metro 并清空缓存npx expo start --clear它等价于把缓存目录删掉再启动遇到诡异问题时先跑这一条能解决掉相当大比例的疑难杂症。4. 常见问题排查还原我踩过的那些坑Expo 在安卓模拟器上跑不起来大多数时候不是配置不对而是某些环境细节没有按预期工作。这一节我把这些年实际遇到的高频问题整理出来从现象到排查不讲虚的。4.1 启动白屏和卡加载先查端口和 Metro 状态现象一模拟器里 Expo 应用打开后白屏或者一直转圈终端没有输出任何报错。这个场景我先看 Metro 的状态。如果 Metro 没有启动或者启动后崩了应用当然拉不到 bundle。最直接的验证办法是打开电脑浏览器访问http://localhost:8081如果能看到一个 JSON 响应或者一个简单的状态页说明 Metro 活着如果访问不通问题就在 Metro 自身重启用npx expo start --clear再看。还有一种情况是端口被占用了。Metro 默认 8081如果你同时开着别的开发服务占了 8081 端口Expo CLI 会提示你换端口。想定位谁占了端口Windows 上执行netstat -ano | findstr 8081macOS 或 Linux 上执行lsof -i :8081找到占用进程后要么结束它要么让 Expo 换一个端口。但换端口后要注意模拟器里的 dev client 默认还是找 8081除非你重新指定所以最简单的做法是释放端口再启动 Metro。现象二界面能打开但一直显示Downloading...或者卡在一个百分比的加载样式。这种多数是网络连接不稳或者资产文件较多加载较慢。可以先等一会儿如果长时间卡住再执行adb reverse手动恢复端口映射因为 adb reverse 偶尔会失效尤其是在模拟器冷启动后。4.2 adb 连不上、设备离线模拟器和电脑之间的通信问题你在终端按a时Expo CLI 提示找不到设备但你明明看到模拟器开着。这种模拟器开了但 adb 不认的情况我遇到太多次了尤其是切换过 Android Studio 版本或者模拟器是从旧快照恢复的情况。第一步先看 adb 识别到的设备列表adb devices正常状态下模拟器会显示为emulator-5554之类并且状态是device。如果显示offline或者列表是空的先试这两条命令adb kill-server adb start-server这一步能解决大部分 adb 假死问题。如果还不行回到 AVD Manager冷重启模拟器Cold Boot删掉模拟器的旧快照再启动。模拟器快照有时候会保存一些错误的 adb 状态冷启动能清掉这些残留。还有一个很少有人注意但容易踩坑的点某些安卓模拟器第三方工具自带独立的 adb 版本如果你电脑里同时有多个 adb 实例版本不一致会导致连接不稳定。建议在环境变量里把 Android SDK 的platform-tools目录放到最前面确保adb --version输出的是你想要的版本。4.3 SDK 版本不一致和依赖问题红色报错信息里如果出现Unable to resolve module、Cannot find module、Invariant Violation这种字眼而且你最近刚改过依赖多数是 SDK 版本匹配出了问题。Expo 有一个很实用的检查命令npx expo-doctor它会扫描当前项目的依赖版本和当前 Expo SDK 做对照指出哪些包版本不匹配。遇到提示后不要手动去npm install一个随意选的版本正确做法是用 Expo 自己的安装工具它会自动选择与该 SDK 兼容的版本npx expo install 包名比如你要用react-native-screens直接跑npx expo install react-native-screens它会把版本给你钉在 Expo SDK 兼容的那一档上比你自己去 npm 页面上猜版本可靠得多。另一个高频原因是 node_modules 的依赖树损坏。我遇到过几次所有代码看起来都没问题expo-doctor 也不报错但模拟器里始终加载不了模块最后靠重新安装依赖解决了。rm -rf node_modules npm install或者用更干净的排障方式先跑npx expo start --clear如果无效再考虑重装依赖。这个组合基本上能覆盖 80% 的改着改着就崩了的情况。4.4 模拟器系统镜像和内存问题变慢卡顿模拟器跑起来之后界面卡顿甚至整个电脑都卡这个问题的概率其实很高。先说结论优先检查 AVD 的分配资源。打开 AVD 的编辑配置看两个值RAM运行内存和内部存储。RAM 如果低于 2GB跑 Expo Go 加上系统服务会比较紧张如果你电脑内存够大但给模拟器分配了超过一半的内存又会导致宿主机无内存可用两边一起卡。比较建议的分配方案是电脑 16GB 内存给模拟器 3GB 到 4GB电脑 32GB 内存给模拟器 4GB 到 6GB。另外模拟器在启动时如果默认使用软件渲染Software GPU跑 Expo 项目里的动画时画面会掉帧严重。在 AVD 配置的 Graphics 选项里改成 Hardware硬件加速之后流畅度会有一个质的提升。由于模拟器需要占用系统资源我自己的经验是把它当作一台运行在电脑里的手机来管理分配资源时讲究平衡而不是越大越好。5. 把开发体验再往上提一档模拟器里的调试技巧环境通了、能跑起来了接下来要考虑的是怎么让日常调试更高效。模拟器不像真机那样需要拿在手里操作但也有一些趁手的小技巧能显著提高开发效率。5.1 快捷键和调试面板速查Metro 终端里支持一组快捷键掌握这几个能省不少事r重新加载整个应用m在模拟器里打开开发者菜单shift m在终端里显示更多菜单选项j打开调试器React DevTools 或 Hermes debuggershift a在 Development Build 中打开项目a在 Expo Go 中打开项目模拟器里的开发者菜单对应真机上的摇一摇手势你可以按Ctrl M直接唤起。在里面能快速切换调试方式、查看日志、刷新 bundle。我在调试布局样式时用得最多的组合是改代码保存然后看界面是否自动刷新。Metro 默认开启 Fast Refresh如果你发现改完代码界面没动静第一反应不是去按r而是检查 Metro 终端有没有输出编译日志。如果终端里显示编译失败问题在代码本身如果没有任何日志才是连接问题。这个判断顺序能帮你快速定位问题范围。5.2 提升模拟器性能的几个设置如果你每天都泡在模拟器里调试还有两个设置值得调整。一个是 AVD 的启动模式Android Studio 默认是 Quick Boot也就是从快照恢复速度很快但偶尔会保留旧状态导致环境不准。我建议在遇到奇怪问题时切换成 Cold Boot手动选一次冷启动排障之后可以再调回 Quick Boot兼顾速度和准确度。另一个是模拟器窗口的比例。调试布局时窗口设置成合适尺寸即可不需要开全屏因为 Metro 终端、代码编辑器、浏览器调试台通常同时开着屏幕空间分配合理更重要。日常我会把模拟器窗口缩到一半旁边放终端和编辑器调试流畅度比全屏更好。还有一个习惯我认为很实用如果你的电脑有多个 AVD建议只保留一个常用的把多余的全部删掉。因为模拟器镜像文件体积很大多套镜像不仅占用磁盘还容易在启动时因为路径混淆产生连接问题。我见过有人电脑里躺着三四个 AVD日常只用一个但每次启动都要小心地选择纯浪费时间。6. 最后再分享一点我的个人习惯和体会跑 Expo 在安卓模拟器上这个场景看起来是环境配置一下就行但它背后牵扯到 Metro、adb、Android SDK、系统镜像、SDK 版本这几条线。我之前帮几个同学排查过发现大家的问题往往不是某一个环节完全不会而是哪里都知道一点但出了问题不知道往哪个方向排查。以我的实际体会来说最高效的调试顺序永远是先确认 Metro 活着浏览器访问 8081再确认 adb 能看到模拟器adb devices最后才是打开 App 看加载状态。把这三个步骤当成肌肉记忆能省掉很多盲目的重启和重装。还有一个取舍想提醒你如果你的项目最终要打包上线不要等到最后一刻才生成开发构建。最好在项目里用到第一个原生依赖时就切到 Development Build让编译流程早点成为习惯。否则到后期才切首次编译的依赖下载、Gradle 配置、SDK 版本对齐会堆在一起问题会变得非常难排查。工具是固定的但每个项目的坑不一样。希望这篇内容能帮你把 Expo 和模拟器这层关系理顺至于那些奇怪的报错信息多看几次多试几次如果你耐心按照连接链路去排查你会发现大部分问题其实都逃不出那几个原因。