Expo Development Build

·14 分钟阅读

1、为什么必须放弃 Expo Go

这是 Expo 学习体系中最核心、最具有分水岭意义的一个概念。理解了它,你就真正跨越了"玩具期",进入了"专业级跨平台开发"的领域。

我们先来破除一个常见的误区:放弃 Expo Go,绝不意味着放弃 Expo 框架本身! 你依然在使用 Expo 的路由、API 和打包服务,你只是不再使用那个名叫 "Expo Go" 的扫码 App 了。

那为什么必须放弃它?答案很简单:因为 Expo Go 是一个"写死了"的沙盒(Sandbox)。

当你从 App Store 或官网下载 Expo Go 时,你下载的是一个已经由 Expo 官方预先编译好的完整原生 App。在这个 App 的底层(iOS 的 Objective-C/Swift,Android 的 Java/Kotlin)里,官方帮你塞进去了几十种常用的原生模块(如相机、相册、位置等)。当你扫码时,Expo Go 只是把你的 JavaScript 代码下载下来,然后去调用它肚子里已经有的原生模块。

局限性

假设现在老板提了一个需求:"App 要接入微信登录,还要接入支付宝支付,推送要用极光推送。"

你兴冲冲地安装了 react-native-wechat-lib(微信 SDK),结果一跑,Expo Go 直接红屏崩溃了!为什么?因为微信 SDK 包含了微信自己写的原生代码(C++/Java/Objective-C),而你手机里的 Expo Go 是从应用商店下载的,它的肚子里根本没有微信的原生代码。

一个简单的判断标准:只要一个第三方库的文档里写着以下任意一条,它在 Expo Go 里就跑不起来:

  • "请运行 pod install"(iOS 原生链接)
  • "请修改 android/app/build.gradle"(Android 原生链接)
  • "请在 AndroidManifest.xml 中添加特殊权限"

国内上架的硬性要求

如果你的 App 需要上架到华为、小米、OPPO、苹果等应用商店,还会遇到一个绕不开的问题:国内安卓应用商店有一个死规定——App 首次启动时,在用户同意《隐私政策》之前,绝对不能初始化任何获取设备信息的原生 SDK。

要实现这个拦截,你必须在安卓最底层的 MainApplication.kt 里写拦截逻辑,或者修改 AndroidManifest.xml。Expo Go 无法让你修改这些底层文件。

NOTE 总结:只要你的应用需要超出 Expo 官方提供的那几十个基础模块之外的原生能力(如微信、支付宝、各大厂商 SDK、特定硬件驱动、底层配置修改),你就必须放弃 Expo Go。

2、什么是 expo-dev-client

既然 Expo Go 跑不起来第三方原生 SDK,那传统的 React Native 开发是怎么做的?以前,大家会执行 expo eject(弹出),把项目变成一个纯原生项目,然后用 Android Studio 和 Xcode 去缓慢地编译。但这样做会彻底丢失 Expo Go 那种"扫码即看、极速热重载、错误提示友好"的开发体验。

为了解决这个痛点,Expo 官方推出了 expo-dev-client

用一个比喻来理解:

  • Expo Go 就像一辆公交车:路线固定,车里有什么配置早就定好了。你可以随时上车(扫码预览),但你不能要求司机把公交车改成敞篷跑车。
  • expo-dev-client 就像是你自己打造的私家车:你想装什么引擎(微信 SDK、支付宝 SDK、极光推送)都可以。更妙的是,这辆私家车里安装了和公交车一模一样的"智能仪表盘"(即热重载、网络调试、扫码加载 JS 的能力)。

从技术角度来说,expo-dev-client 是一个 npm 包。当你把它安装到项目里,并进行一次原生构建后,它会生成一个专属于你这个项目的"定制版 Expo Go" App。在这个"定制版 App"里:

  • 包含了你引入的所有第三方原生 SDK(比如微信、支付宝)
  • 包含了你自己修改的原生配置(比如隐私弹窗拦截)
  • 同时保留了开发菜单(摇晃手机呼出)、React 开发者工具、极速 Hot Reload 的能力

NOTE 构建完成后,这个 App 的图标默认会带有一个小齿轮标记,表示它是开发版。

3、安装与配置

安装 expo-dev-client

在你的 Expo 项目根目录下执行:

npx expo install expo-dev-client

这条命令会自动安装兼容当前 Expo SDK 版本的 expo-dev-client,并更新 package.json

NOTE 使用 npx expo install 而非 npm installyarn add,是因为 Expo CLI 会自动选择与当前 SDK 版本兼容的包版本,避免版本冲突。

生成原生工程(Prebuild)

安装完 expo-dev-client 后,你需要生成原生工程代码:

npx expo prebuild

这条命令会根据 app.json / app.config.js 中的配置,在项目根目录生成 ios/android/ 文件夹,包含完整的原生工程代码。

执行过程中,CLI 会提示你输入 iOS Bundle Identifier 和 Android Package Name(如果还没有在配置中指定的话):

? What would you like your iOS bundle identifier to be?
› com.yourname.myapp

? What would you like your Android package name to be?
› com.yourname.myapp

NOTEprebuild 是幂等操作。如果你修改了 app.json 中的配置,可以运行 npx expo prebuild --clean 重新生成原生工程。--clean 会先删除现有的 ios/android/ 目录再重新生成。

在 app.json 中配置

确保你的 app.json 包含必要的配置项:

{
  "expo": {
    "name": "my-app",
    "slug": "my-app",
    "ios": {
      "bundleIdentifier": "com.yourname.myapp",
      "supportsTablet": true
    },
    "android": {
      "package": "com.yourname.myapp",
      "adaptiveIcon": {
        "foregroundImage": "./assets/adaptive-icon.png",
        "backgroundColor": "#ffffff"
      }
    },
    "plugins": [
      "expo-dev-client"
    ]
  }
}

expo-dev-client 添加到 plugins 数组中,确保 prebuild 时正确注入开发工具。

4、构建与运行

本地构建

生成原生工程后,你可以直接在本地构建并运行:

iOS(需要 macOS + Xcode):

npx expo run:ios

Android(需要 Android Studio + SDK):

npx expo run:android

这些命令会:

  • 编译原生代码,生成开发版应用
  • 自动安装到模拟器或已连接的真机
  • 启动 Metro 开发服务器
  • 应用启动后自动连接到开发服务器

首次构建需要编译全部原生代码,后续构建会利用缓存显著加速。

NOTE 本地构建要求你已经配置好完整的原生开发环境(Xcode / Android Studio)。如果你不想配置本地环境,可以使用 EAS Build 在云端构建。

使用 EAS Build 云端构建

CAUTION 暂时仅做了解,后续会更详细的介绍 EAS Build

EAS(Expo Application Services)提供云端构建服务,无需本地原生环境。

第一步:安装 EAS CLI 并登录

npm install -g eas-cli
eas login

第二步:配置 EAS Build

eas build:configure

这会在项目根目录生成 eas.json 配置文件:

{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal"
    },
    "preview": {
      "distribution": "internal"
    },
    "production": {}
  }
}

其中 development 配置项是专门为 Development Build 准备的:

  • developmentClient: true 表示这是一个开发构建,会包含调试工具
  • distribution: "internal" 表示用于内部分发(不上架应用商店)

第三步:触发构建

# 构建 Android 开发版
eas build --profile development --platform android

# 构建 iOS 开发版
eas build --profile development --platform ios

# 同时构建双平台
eas build --profile development --platform all

构建完成后,EAS 会提供下载链接或二维码,直接安装到设备上。

启动开发服务器

Development Build 安装到设备后,启动开发服务器:

npx expo start --dev-client

然后在设备上打开你构建的应用,它会显示一个开发者菜单界面,你可以:

  • 输入开发服务器地址手动连接
  • 扫描终端中的二维码自动连接
  • 从历史记录中选择最近连接过的服务器

连接成功后,开发体验与 Expo Go 完全一致——Fast Refresh、错误覆盖层、开发者菜单一应俱全。

5、开发工作流的变化

引入 expo-dev-client 后,你的开发流程会从以前的模式发生明显变化。

以前使用 Expo Go:

  1. npx expo start 启动开发服务器
  2. 拿手机里的公共 Expo Go 扫码
  3. 只能写 JS 代码,不能加原生库

现在使用 Development Build:

  1. 安装第三方原生库(例如 npm i react-native-wechat-lib
  2. 安装 expo-dev-client:npx expo install expo-dev-client
  3. 构建定制 App(最关键的一步):执行 npx expo run:androideas build --profile development
  4. 把构建出的 App 安装到测试手机上
  5. npx expo start --dev-client 启动开发服务器
  6. 打开你安装的"定制版 App",它会自动连接开发服务器,加载你的 JS 代码

现在,当你修改 JS 代码并按下保存时,画面依然会像 Expo Go 一样瞬间刷新;同时,当你的 JS 代码调用 Wechat.login() 时,它能完美地唤起原生微信,因为这个定制 App 的肚子里已经有微信 SDK 了。

何时需要重新构建

理解这个边界非常重要:原生代码变更时需要重新构建,但纯 JS/TS 变更不需要。

需要重新构建不需要重新构建
安装/删除包含原生代码的库修改 JS/TS/JSX/TSX 代码
修改 app.json 中的原生配置修改样式、组件逻辑
添加或修改 Config Plugin安装纯 JS 包(如 lodash、dayjs)
升级 Expo SDK 版本修改 Metro 配置

NOTE 大部分开发时间你都不需要重新构建。只有涉及原生层变更时才需要。这让 Development Build 的日常体验和 Expo Go 非常接近。

6、总结

expo-dev-client 让你在保留 Expo 开发体验的同时,拥有完整的原生代码控制权。它是从"学习模式"迈向"专业开发"的关键一步。

行动指南:

  • 在系统学习的前期,安心使用 Expo Go,因为它最简单、最快
  • 当你需要接入第三方登录、支付、推送,或者处理国内上架的隐私合规时,就是你安装 expo-dev-client、打出第一个 Development Build 的时刻
  • 放弃 Expo Go 不是放弃 Expo——你只是从公交车换成了私家车,路还是同一条路