恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
EAS+Fastlane搭建React Native多端自动化打包发布流水线
首页
资讯中心
/
EAS+Fastlane搭建React Native多端自动化打包发布流水线
EAS+Fastlane搭建React Native多端自动化打包发布流水线
发布时间:2026/9/18 11:11:37
周一早上九点一刻产品经理在群里问“今天的测试包什么时候出”你的代码昨天半夜才合并手头这台2020款 Intel Mac 编译一个 iOS 包要二十分钟起步中间还不能开浏览器。这种场面我相信每个做过 React Native 工程化的同学都不陌生——而如果你同时维护 App Store 和 Google Play 两个商店、还有 TestFlight 和 Play 内测通道打包这件事的复杂度会瞬间从“有点烦”变成“想掀桌”。我选择的破局方案是 EAS 加 Fastlane 的组合EAS 负责云端构建签名Fastlane 负责上传商店和证书把从 push 代码到商店上架的链路压缩成一条自动流水线。这篇文章不是工具文档的翻译是我把整套多端自动化打包发布体系从零搭到“每周稳定出包”的完整记录适合正在搭建移动端持续交付流程、或者被“怎么又说本地编不过”逼疯的工程团队参考。1. 手动打包的至暗时刻为什么“多端”不只是跑两遍命令1.1 打包不是“编译一下”是环境的全面博弈很多人第一次接触 React Native 项目时会觉得“一次编写到处运行”就意味着打包也很简单iOS 跑一遍、Android 跑一遍完事。但真实情况远没有这么体面。iOS 打包要求 Mac 系统、Xcode 版本、CocoaPods 依赖、开发者证书和描述文件全部对齐Android 打包要求 JDK 版本、Android SDK、Gradle 版本、keystore 签名文件一个都不能乱。这几个要素只要有一个不一致换台机器、换个时间、甚至换个网络环境结果都可能不一样。我自己就遇到过最经典的场景同事的 Mac 上能正常打出 iOS 包代码一样、分支一样拉到我电脑上就是证书找不到今天能编过的项目升级了一次 Xcode第二天构建脚本就开始报错。这种“环境玄学”最可怕的地方在于它不可复现也经不起追问。你很难告诉产品经理“这个包在张同学的电脑上才能出”因为这在工程上就是灾难。所以多端自动化打包发布要解决的第一个问题不是“跑两遍命令”而是“让构建环境彻底可复现、可迁移、可审计”。这也是为什么云构建方案在近两年变成了移动端工程化的主流答案——它把“在你电脑上能跑”变成了“在所有机器上都能跑”。1.2 多端背后的真实含义平台、渠道与团队协作再往深一层看“多端”其实包含了三个维度的复杂性这也是我最初低估的地方。第一个维度是操作系统的多样性iOS 和 Android 的构建链、签名体系、商店规则完全不同。第二个维度是发布通道的多样性同一个版本可能要出 development build 给开发自测出 preview 给测试团队验收出 production 给商店审核还要发 TestFlight 内部测试和 Play 内测通道。每条通道的签名配置、版本号规则、分发对象都不一样。第三个维度是人的协作当团队里有四五个人都在动打包配置时如果没有统一平台光“谁的证书过期了”“keystore 到底存在哪”就能耗掉半天。这套流程真正跑顺之后我最大的感受是所谓“工程化终局”不是某个工具单打独斗而是每个环节都有清晰的责任边界——构建归构建签名归签名上传归上传测试归测试谁也别越界谁也别掉链子。EAS 和 Fastlane 的组合恰好就是在这些边界上各司其职。2. EAS Build 把“构建”搬上云端签名、缓存和免费额度的是非题2.1 EAS Build 的核心机制环境一致性从哪里来EASExpo Application Services是 Expo 官方推出的应用服务套件其中 EAS Build 解决的就是“构建环境一致性”的问题。它的做法很直接把构建过程放到 Expo 托管的云端机器上执行这些机器已经预装好了指定版本的 Xcode、JDK、Android SDK 和 Node.js每次构建都从干净环境开始。这意味着什么意味着你再也不需要用“我这台机器 2019 年装的 CocoaPods 一直没敢升级”这种借口来解释构建失败。EAS Build 每次拉取代码后会按照项目里的配置重新安装依赖、执行构建命令然后返回一个可安装的产物。整个过程里本机只需要有 Git 和 EAS CLI连 Xcode 都不用装。我用一个比较生活化的类比理解这件事以前的打包像在自己家厨房做菜调料、灶台、锅具都是自己的火候全凭感觉EAS Build 像去中央厨房食材带过去设备是标准化的出品质量稳定。对团队来说这省掉的不仅是环境维护成本还有一种看不见的“隐性知识”——那些只存在于某个人电脑里的构建秘诀从此不再重要。2.2 凭证仓库解决了团队里最头疼的“那把钥匙”构建过程中最敏感的环节是签名。iOS 需要 Distribution Certificate 和 Provisioning ProfileAndroid 需要 keystore 文件。手动管理这些凭证时最常见的问题是“钥匙只有一把人却有好几个”。EAS Build 内置了凭证管理能力可以统一托管 iOS 的证书和描述文件、Android 的 keystore并在云端构建时自动完成签名。第一次运行eas build时它会引导你创建或上传凭证之后这些凭证就加密保存在 EAS 服务端。团队成员不再需要互相拷贝.p12文件和 keystore 文件也不用担心证书私钥在微信传来传去导致泄露。这块我必须说一句凭证管理是工程化里最容易被低估、出事时最致命的一环。我见过有团队把 Android keystore 放在项目的android/目录下直接提交到 Git后来仓库公开整包被人拿去重签名。把凭证交给 EAS 托管之后至少权限边界清晰了——谁是项目管理员、谁能触发构建、谁能查看凭证都有迹可循。2.3 免费额度到底够不够用“eas 云端构建免费吗”这个问题在开发者社区里被反复问起我也被问过很多次。我的回答是对于个人项目和小团队来说EAS 的免费额度基本够用但需要理解它的分层逻辑。EAS 的免费档位里development profile 的构建额度相当充裕适合日常开发调试production profile 的生产构建每月有免费配额超出后按构建次数或时长计费。很多个人开发者的发布频率是“一周一版”甚至“一月一版”完全落在免费额度内。如果你的团队每天要出好几个生产包那确实需要评估付费计划。我个人的建议是不要把免费额度当成“白嫖资源”去扣而是把它当成一个信号——如果项目已经跑到了每月需要大量生产构建的阶段说明产品进入了稳定迭代期这时候花钱买稳定的构建队列和更快的构建速度性价比非常高。省下来的不是钱是整个团队的时间。3. Fastlane 接管“最后一公里”上传商店与签名证书的管理分工3.1 Fastlane 在整条链路中的位置EAS Build 把安装包构建出来之后下一步是上传到应用商店同时处理 TestFlight 的内部测试分发、App Store 的审核提交、Google Play 的上架更新。这一环节 Fastlane 是绕不开的老牌选手。Fastlane 是用 Ruby 写的开源自动化工具它最擅长的就是“商店操作自动化”。pilot负责上传 TestFlight 并管理测试员deliver负责上传 App Store 的版本信息、截图和构建包supply负责 Google Play 的上传和版本发布。还有match这一套专门用来管理证书签名它会把证书加密后放到一个 Git 仓库里团队拉到同一套签名就能各自打正式包。用一句话概括分工EAS 管“构建”Fastlane 管“上传”和“商店元数据”。两者不是竞争关系而是上下游关系。EAS 把 iOS 的.ipa和 Android 的.aab交到 Fastlane 手里Fastlane 负责把这些产物准确、合规地送进各个商店后台。3.2 用一条 lane 打通 iOS 与 Android 上报Fastlane 的配置核心是Fastfile里面定义了一个个lane。每个 lane 是一段自动化流程的命名比如“打 iOS 内测包”“提审 App Store”“上传 Play 正式版”。你可以把多个操作串在一起形成一条完整的发布流水线。我常用的做法是维护一个双平台统一入口 lane。举个例子在Fastfile里写platform :ios do desc Upload iOS build to TestFlight lane :upload_testflight do pilot( skip_waiting_for_build_processing: false ) end end platform :android do desc Upload Android build to Play Console internal testing lane :upload_internal do supply( track: internal, aab: build/app-release.aab ) end end这样团队发布时只要执行fastlane ios upload_testflight或fastlane android upload_internal不用去各商店后台点鼠标。上传之后的构建处理状态、测试员邀请、版本说明填写都能在 lane 里追加配置。把重复操作封装成 lane本质上是在把“人对流程的记忆”转译成“代码对流程的固化”。3.3 EAS Submit 与 Fastlane如何选看到这里你可能会问EAS 不是自带eas submit吗为什么还要再引一个 Fastlane确实EAS Submit 也能上传到 App Store Connect 和 Google Play Console对轻量场景完全够用。但我的判断标准是“复杂度到没到那条线”如果只是把构建产物传上去EAS Submit 更简单少装一套 Ruby 环境如果后续要做商店元数据批量更新、截图自动生成、多应用批量发版、或者接入别的自定义脚本Fastlane 的生态明显更成熟。拿我自己来说项目早期我只用 EAS Submit后来越发越频繁开始需要自动更新版本说明、同步测试员列表、甚至对接内部 IM 通知EAS Submit 就有些吃力了。Fastlane 则像一个瑞士军刀你总能找到对应的 action 或者直接插入一段 Ruby 脚本处理特殊需求。最终我选择的是“EAS Build 构建 Fastlane 上传”的组合这也是我认为当前生态里最稳的一条路径。4. 从零搭到每周稳定出包EAS 与 Fastlane 的完整配置链路4.1 初始化项目与登录授权无论你项目里是否已经开始使用 Expo 的 API只要它是 React Native 工程要享受 EAS 的云端构建服务就需要先安装并登录 EAS CLI。npm install -g eas-cli eas login登录成功后在项目根目录执行eas init这个命令会在项目里生成eas.json配置文件同时把当前项目关联到你在 Expo 账号下的应用记录里。这里要注意eas init还会要求确认app.json或app.config.js里的ios.bundleIdentifier和android.package是否已经填写这是云端构建识别应用身份的关键字段建议从项目开始就定好不要中途修改否则会引发一系列签名和商店映射问题。EAS 登录授权环节经常会卡住新手——浏览器弹出 OAuth 授权后终端会等待回调。如果你在远程服务器上操作没有本地浏览器可以用eas login --sso或者手动复制授权链接到本地浏览器打开。小团队的 CI 机器建议用项目级 token 方式避免在公共机器上保存账号密码。4.2 编写 eas.json构建配置的核心eas.json是 EAS Build 的核心配置文件里面按 profile 区分不同的构建场景。我一般维护三个 profiledevelopment、preview、production。{ cli: { version: 5.0.0, appVersionSource: remote }, build: { development: { developmentClient: true, distribution: internal }, preview: { distribution: internal, android: { buildType: apk } }, production: { autoIncrement: true } }, submit: { production: {} } }几个关键配置我展开说明一下。cli.appVersionSource设置为remote是我强烈推荐的做法它让版本号由 EAS 服务端统一管理每次构建自动递增buildNumberiOS和versionCodeAndroid从根上解决团队多人构建时版本号冲突的问题。development.profile里的developmentClient: true表示生成的是 Expo 开发客户端适合开发阶段安装到真机调试。preview的distribution: internal配合android.buildType: apk目的是生成一个可以直接安装的 APK方便分发到测试群不用走 Play Console 的签名流程。iOS 上对应的preview会生成 ad-hoc 签名的 ipa可以装到注册过的测试设备上。production的autoIncrement: true是配套版本自动递增的开关。这样主版本号通过手动改app.json控制构建号由 EAS 自动加一逻辑清晰也不会撞号。4.3 Fastfile 与 .env 环境变量Fastlane 侧除了Fastfile我还会准备一个.env文件来保存 App Store Connect API Key 的路径、Google Play service account 的 JSON 路径、以及需要上传的渠道名。环境变量不应该写死在Fastfile里既是为了安全也是为了不同环境复用同一份 lane 配置。一个比较完整的Fastfile骨架是这样的default_platform(:ios) platform :ios do desc Upload to TestFlight lane :upload_testflight do pilot( skip_waiting_for_build_processing: false, changelog: Automated build from CI ) end desc Upload to App Store lane :upload_appstore do deliver( skip_screenshots: true, skip_metadata: true, force: true ) end end platform :android do desc Upload to Play Console internal track lane :upload_play_internal do supply( track: internal, aab: build/app-release.aab, skip_upload_metadata: true, skip_upload_images: true ) end endpilot的skip_waiting_for_build_processing参数值得注意。默认它为false意思是上传后 Fastlane 会一直等待 TestFlight 处理完构建包。对 CI 来说这一步可能会让任务挂 10 到 20 分钟所以如果你想加快流水线可以把它设为true让它上传完就返回处理状态后续通过邮件或者接口查询。Android 侧的supply我习惯只在发布内部测试轨道internal时自动化正式轨道仍然保留人工确认环节。自动化做得好不代表所有环节都要全自动涉及线上发布的动作保留一个“人”的确认点反而更安全。4.4 GitHub Actions 接入 CI自动化流程本地能跑通之后接入 CI 才是关键一步。我使用 GitHub Actions 作为调度层触发条件设置为“手动运行”和“打 tag 时自动运行”两种。.github/workflows/release.yml的简化版name: Release on: workflow_dispatch: inputs: platform: description: ios / android / all required: true default: all push: tags: - v* jobs: build-and-submit: runs-on: ubuntu-latest steps: - uses: actions/checkoutv4 - uses: actions/setup-nodev4 with: node-version: 20 - name: Install dependencies run: npm ci - name: Install EAS CLI run: npm install -g eas-cli - name: EAS build run: eas build --platform ${{ github.event.inputs.platform || all }} --profile production --non-interactive env: EXPO_TOKEN: ${{ secrets.EXPO_TOKEN }} - name: Upload via Fastlane run: fastlane ios upload_testflight env: APP_STORE_CONNECT_API_KEY_PATH: ${{ secrets.ASC_API_KEY_PATH }}几个细节需要强调CI 用的EXPO_TOKEN不是登录密码而是在 Expo 账号设置里生成的访问令牌专门给 CI 使用。GitHub Secrets 里配置令牌后eas build才能以非交互模式运行。Fastlane 在 CI 上运行 iOS 上传任务时理论上需要 macOS 环境因为 App Store Connect API key 的上传动作不依赖 Xcode所以 Linux runner 上也能跑。但如果你需要在上传前执行gym重新打包那就必须用macos-latestrunner。我的配置里把构建交给了 EASFastlane 只做上传所以 ubuntu runner 就够了。4.5 第一次端到端验证配置写完之后第一次端到端跑通是最兴奋也最容易出问题的时候。我的建议是从最小闭环开始先用eas build --platform android --profile preview打一个 Android 测试包确认产物能正常安装再用fastlane android upload_play_internal上传到 Play Console 内部测试轨道确认商店后台能看到版本最后再跑 iOS 侧确认 TestFlight 能收到构建。不要一上来就全平台同时跑虽然 EAS 支持--platform all但 iOS 的证书配置一旦出错整个任务会卡很久。一个小技巧是在eas build之前先跑eas credentials命令手动检查和配置当前项目的凭证确认“钥匙已经配好”再进流水线能省很多排查时间。5. 我在真机上踩过的坑签名冲突、缓存过期与版本号失控5.1 证书不一致导致的上传被拒EAS 的 iOS 构建上传到 TestFlight 后有时会收到类似 “Missing Provisioning Profile” 的邮件或者 App Store Connect 直接显示 “Invalid Binary”。这类问题十有八九出在证书和描述文件不匹配上。我遇到过一次是因为团队里有人用 Xcode 手动导出过 ipaXcode 自动生成了一个新的 provisioning profile 并上传到了 Apple Developer 后台而 EAS 云端保存的凭证还是旧的。两边内容对不上构建出来就废了。解决办法是到 EAS 凭证管理里强制重置让它重新生成或重新上传一套匹配的证书。这里我学到的教训是iOS 签名相关的所有操作务必统一走 EAS 或 Fastlane match不要少数人用 Xcode 手动瞎点。签名这件事最怕的就是“两条腿走路”最后自己都不知道哪套凭证是当前生效的。5.2 EAS 缓存引发的“构建成功但没生效”云端构建听起来每次都是干净环境实际上 EAS 也有缓存层。依赖安装缓存和 Gradle 缓存是为了加速构建但偶尔会带来“代码改了构建成功装上却不是新代码”的诡异问题。有一次我改了一个原生模块的配置重新跑eas build --profile preview产物安装到手机上功能完全没有变化。排查了半天发现是 EAS 命中了旧的依赖缓存没有重新执行某些原生构建步骤。解决方式有两种一是在eas.json里给对应 profile 设置cache.clear: true强制本次构建不读缓存二是在项目里调整缓存策略比如把容易变化的原生构建步骤单独列出避免缓存命中。日常开发中我不建议每次都清缓存否则构建速度会变慢但当出现“改了原生代码但没生效”的诡异现象时第一个怀疑的就应该是缓存。5.3 版本号失控与 appVersionSource版本号失控是我见过团队协作中最普遍的坑。多人手动打包时经常出现“Version 1.0.0 Build 3”已经传到 TestFlight另一个人不知道又打了个“Build 3”出来App Store Connect 直接报错提示版本号已存在。配置了appVersionSource: remote之后这种情况基本就杜绝了。EAS 云端会维护每个平台的构建号你只管改语义化版本号构建号由服务端递增。这个配置看上去只是几行 JSON实际上是“多端自动化”里的一个隐形基石——它消除的是团队协作里最琐碎也最容易吵架的那类冲突。6. 把流水线接到 CI并留给 AI 时代的位置6.1 从“一键出包”到“push 即发布”工程化做到这一步团队里的日常体验已经完全变了开发合并代码、push tagGitHub Actions 检测到标签后自动跑 EAS 云端构建构建结束自动下载产物、上传 TestFlight 和 Play 内测消息通知到 IM 群。整个过程不依赖任何人的电脑也不依赖某个人“今天在不在工位”。我自己的体会是工具链搭建只是表象真正变化的是团队心智。以前大家把“打包”当成一件事需要有人专门负责现在打包变成了流水线里的一个中间步骤每个人都可以在需要时走进发布流程也能在出问题时根据日志快速回溯。这种“可重复、可追踪、可回滚”的发布状态才是我理解的工程化终局。6.2 给自动测试在流水线中留一个位置构建和发布自动化跑通之后下一步自然就是把质量检查塞进流水线。目前社区里讨论很多的“AI 自动写测试用例、自动跑测试、自动代码 review”本质上也是把质量门禁往前移。现在像 Harness 这类 CI/CD 平台已经在推 AI 生成测试用例和代码评审的能力EAS 本身也支持在构建前挂自定义 hook 执行测试脚本。我的做法是至少在 CI 里跑单元测试和静态检查测试不过就不允许触发 EAS 构建。至于 AI 生成的测试用例它不能替代人工写核心用例但很适合做边界场景补充、异常分支覆盖以及回归测试的快速铺量。这个方向我认为是移动端工程化未来两三年最大的变量。打包上架这件事已经没有太多新东西可玩但“让机器更懂你的业务代码自动生成测试和审查意见”还有很大想象空间。哪怕现在只做最基础的“测试不通过不出包”也已经比大多数团队往前走了一大步。6.3 工程化不是终点是持续演进回看这套体系里投入的时间大部分并不花在“敲命令”上而是花在理解每个环节为什么要这么设计。比如 EAS 为什么要把凭证托管到云端Fastlane 为什么设计了 lane 和 match 这种抽象CI 为什么要把触发放到标签上而不是每次提交都跑。理解了这些之后你会发现工程化根本没有“终极答案”它更像是一条持续演进的路。今天用 EAS 和 Fastlane明天可能换成公司内部的构建平台今天手动维护Fastfile明天可能用可视化编排工具替代。但只要底层逻辑是对的——环境可复现、凭证可管理、流程可追踪、质量有门禁——无论上层工具怎么变这套工程化体系都不会塌。我在实际运行中最推荐的一个小技巧是把 EAS 构建和 Fastlane 上传拆成两个可独立触发的 job中间通过构建产物传递。这样失败重跑时不用整条链路重新走单独重跑上传步骤就行。踩过几次坑之后你会明白自动化流程里“可局部重试”和“可全局重跑”的差距往往就是“今天能不能准时下班”的差距。