无论怎样都要快速构建:Expo 如何优化速度(以及你也能怎么做)

新款 M4 Mac Mini、编译器缓存和预编译二进制文件正在加速 EAS 构建。了解如何借助指纹和 OTA 更新减少构建次数。

中文
复制
Build fast, no matter what: how Expo is optimizing for speed (and how you can, too)

你需要速度。

无论你是学生,在课间发布自己的第一个应用;还是工程师,趁午休时间偷偷推进自己的副业项目;又或者身处企业团队,要为几百万用户负责——约束条件都一样。你没时间等构建。你需要立刻拿到反馈。你需要趁想法还热乎的时候把它发出去。

构建一慢,势头就断了。构建够快,你才能一直待在心流里,而好产品恰恰是在这种状态下做出来的。

我们的目标是不管你用的是哪个套餐,都给你最快的构建。**为了兑现这个承诺,我们正在采取措施,应对 Expo 前所未有的需求、Mac 硬件短缺,并扩展规模以满足企业工程师和 vibe coder 这两类用户的需要。

对于用 OpenClaw 做 AI 自动化的玩家来说,Mac Mini 是抢手货,尤其是那些内存更大的配置(内存本身早就是稀缺资源了)。如果你看过我们的构建服务器配置页面,就知道 iOS 构建跑在配置拉满的 M4 Mac Mini 上。Mac Mini 全球发货周期拉长,再加上全世界 vibe coder、独立开发者、本地商家和企业掀起的应用开发热潮,这几件事凑到一起,你自然会想知道这会不会影响 Expo 的 Build 和 Workflows 队列。

以下是我们为加快构建、扩充基础设施正在做的事:

  • 首先,我们最近已经往集群里加了几十台新的 M4 Pro 和 Max Mac Mini,眼下还在继续上架,另外还有更多已经下单、正在路上。

  • 我们正在采取多项措施让每次构建都更快,这意味着每个人都能跑更多构建。

    • 我们最近为 SDK 54 和 55 项目部署了编译器级缓存,把你的 fastlane 和 gradlew 步骤提速最多 30%。

    • 我们正在部署 Gradle 缓存,以提升 Android 构建性能。

    • 我们正在为 react-native-reanimatedreact-native-screens 这类常用包加入预编译二进制,基本上可以消除构建这些产物所需的时间。

  • SDK 56 为 iOS 上最复杂的 Expo 模块提供预编译 XCFrameworks,以加快 iOS 构建速度。

我们的愿景是让每位构建者都有机会做出真正的东西。第一次用 Expo,构建飞快完成时,你能感受到。然后它再次发生,到某个时候你完全不再去想构建这件事。你相信一切都会正常工作,而且会很快。这就是我们的标准:让你不必操心基础设施,从而专注于构建美好的东西。

同样的标准也适用于我们的工具。我们的开发者工具应当帮助你充分利用每一次构建,也让你更容易发挥自己硬件的性能。

用基于指纹的工作流减少构建次数

还有什么比在启用了 ccache 和预编译 React Native 二进制的 EAS M4 Max large worker 上构建更快?干脆不构建怎么样?

即使你不需要 Expo 的 OTA Updates 来向生产应用空中推送 bug 修复,它也非常适合让你的预览应用反馈循环尽可能紧凑。大多数应用不需要在每次代码改动时都完整重新构建,因为大多数改动只涉及 JavaScript。相反,推送一次更新,只重新构建 JavaScript,让你已安装的应用下载新代码即可。

运行 eas update:configure 将应用配置为使用 EAS Update 并重新构建。你可以用动态应用配置只为预览应用启用更新(这种情况下把 updates.enabled 设为 false)。

之后,当你确定没有改动任何原生代码或依赖时,可以运行 eas update --channel preview 手动更新应用。或者,把它配置成一个 EAS workflow在提交时自动运行,并根据原生指纹的采样结果选择构建还是更新——指纹是一种哈希,只有原生代码变化时才会改变。

把 Expo 项目连接到 Github,然后把这个 workflow 加到 .eas/workflows 文件夹:

name: Build or update preview on main push, based on fingerprint

on:
  # Trigger on pushes to main branch
  push:
    branches: [main]

jobs:
  fingerprint:
    environment: preview
    type: fingerprint

  ios_get_build:
    needs: [fingerprint]
    type: get-build
    params:
      fingerprint_hash: ${{ needs.fingerprint.outputs.ios_fingerprint_hash }}
      platform: ios
      profile: preview

  ios_update:
    needs: [ios_get_build]
    if: ${{ needs.ios_get_build.outputs.build_id }}
    type: update
    params:
      channel: preview
      platform: ios

  ios_build:
    needs: [ios_get_build]
    if: ${{ !needs.ios_get_build.outputs.build_id }}
    type: build
    params:
      platform: ios
      profile: preview
      
  # add the same steps for Android to handle those builds/updates, as well!

完整示例见文档

为应用加上 EAS Update,并尽可能用它来更新代码,是让每次构建发挥最大价值的好办法。

在本地构建,用于开发和测试

npx expo start 启动本地开发服务器、在 Expo Go 或 development build 里跑应用,大概是 Expo CLI 最常见的用法。不过必要时,Expo CLI 也能直接把应用构建并运行在模拟器或真机上

准备工作

本地构建时,Expo CLI 会调用你已安装的 Android Studio 或 Xcode,使用其中的原生开发工具。这些工具的配置稍有不慎就会出问题,所以我们准备了一份本地构建指南,给出了经过验证的 AndroidiOS 构建配置。注意,iOS 构建需要一台 Mac。

本地 development build

原生工具装好之后,就可以用下面的命令在模拟器上构建并运行应用:

npx expo run:android

或者

npx expo run:ios

这会为应用生成 debug build,并启动本地开发服务器(也就是 npx expo start 做的事)。也就是说,你不仅在本地完成了构建,还能在编辑 JavaScript 代码时实时重载。

第一次运行这条命令时,它还会执行 npx expo prebuild 来生成 android 和 iOS 原生目录。如果你添加了带原生代码的包,或者改动了 app.json,通常需要运行 npx expo prebuild --clean 重新生成这些目录,再运行 npx expo run:android|ios 重新构建。这大致相当于 EAS 每次构建应用时做的事。

装上 expo-dev-client 之后会更方便。这个包能把任意 debug build 变成 development build,让你可以打开任意开发服务器的 URL。development build 一旦装到模拟器上,只要原生运行时不变,就不必反复重新构建。直接运行 npx expo start,按 a 在 Android 上打开,按 i 在 iOS 上打开。

Release build

有些东西在 development build 里不太好测,启动屏尤其如此。你仍然可以用本地构建完成大量上线前的测试——构建一个独立的 release build:

npx expo run:android --variant release

npx expo run:ios --configuration Release

共享构建

通过 EAS,你可以把在本机构建的 Android APK 构建和 iOS 模拟器构建共享给组织内的其他开发者。运行 eas upload 手动上传构建并生成可共享的链接,或者把 EAS 配置为构建缓存提供方来自动完成这一步。之后其他开发者运行 eas build:run 即可下载并运行该构建。

设备构建

npx expo run:android|ios 还可以把构建运行在通过 USB 连接的设备上。

Android 方面,连接 Android 手机并确认已开启 USB 调试后,运行 adb devices -l 获取设备名称,再把该设备名称填入 npx expo run:android --device [device-name]

iOS 方面,连接设备并确认已开启开发者模式,然后运行 xcrun xctrace list devices 获取设备 UDID,接着运行 npx expo run:ios --device [udid]。注意,你可能需要在 Xcode 中打开 ios 文件夹并选择你的开发团队才能完整走完这套配置(如果需要,Expo CLI 会提示你)。

如果你做的是开发构建,只要原生运行时不变,断开 USB 之后仍可继续使用同一个构建。之后运行 npx expo start 并扫描二维码即可。

生成已签名的生产构建

EAS 的凭据管理相当方便,在模拟器、仿真器或已连接设备上运行所需的简单签名配置,就足以支撑大量开发和测试工作,所以不妨把这套本地签名流程当作“紧急情况下才砸玻璃”的备用手段。不过,如果你确实需要用 EAS 生成的生产凭据在本地构建,也是有办法的。

首先,通过 eas credentials 命令下载所需的凭据。它会引导你完成各平台所需的内容(Android 的上传密钥库和 iOS 的分发证书)。然后运行 npx expo prebuild --clean 生成原生项目。如果你使用了多个应用变体,请确保环境已切换到生产变体(如果你是用 EAS 环境变量设置的,可以运行 eas env:pull 在本地设置这些变量)。

Android 端,在 Android Studio 中打开 android 文件夹,进入 BuildGenerate Signed App Bundle or APK,填入刚下载的 keystore。

iOS 端,解压刚下载的凭证并安装到 Keychain。在 Xcode 中打开 ios 文件夹,在 Target 下检查 Signing and Capabilities,确认签名配置无误。重新生成 provisioning profile 可能更省事(这么做没有任何坏处)。然后运行 ProductArchive 进行构建。

结语

本地构建是工具箱里很值得添置的一件,理由很多:从本地原生代码调试,到网络访问限制,等等。它与云端 EAS Build 和 Workflows 互为补充,能在你卡住时帮你脱身,同时其余自动化流程继续在 EAS 上跑。说到自动化,现在也正是引入 fingerprints 和 EAS Update 的好时机——限制重建的频率和时机,迭代速度还能再快一截。

来源: Expo Blog← 返回首页