跳过主要内容

构建类型解释:从本地到生产

困惑于各种构建类型?本指南解释了从本地、CI、调试和发布构建到签名、分发和回滚策略的所有内容。

马丁·多纳迪厄

马丁·多纳迪厄

内容营销

构建类型解释:从本地到生产

你打开一个项目,看到 build:ios:dev, build:android:qa, build:staging, build:release, build:prod,再加上几个 nobody 想要触摸的 shell 脚本。然后有人说,“请在今天晚些时候为客户制作一个预发布构建。”如果你是一个中级的移动开发者,那么这个请求通常会感到很烦恼。哪个配置?哪个签名身份?哪个后端?哪个分发路径?

那種混淆通常源於把建構類型視為平面清單。它們並不是。它們是一個工作流程。每個建構都存在於解決特定的問題在特定的點之間您的筆記本電腦和用戶裝置。

一個建構不僅僅是一個編譯好的應用程式。它是一個為了目的、觀眾和環境而組裝的應用程式版本。有些建構存在於幫助您debug。有些存在於幫助QA安全地破壞東西。有些存在於讓發行工程可以產生可信賴的物件。有些存在於讓產品團隊可以以較少風險發送變更。

如果您的本地設置仍然感到不穩定在任何事情開始之前,先用一個適當的 Capacitor 本地環境設置。建構複雜度變得更容易推理時您的基礎工具是可預測的。

內容表

软件构建的世界

我经常看到的最常见错误是假设构建名称包含了所有信息。它们并没有。 staging 可能意味着“发布版本,指向测试API”。在另一个仓库中,它可能意味着“可调试的QA artifact,模拟支付”。在第三个仓库中,它可能意味着“私有发布的生产签名构建”。

因此,团队会陷入混乱。标签只有在您了解该构建正在执行的工作时才有用。

思考构建类型的有用方法是这样的:

  • 本地构建 帮助个人开发者快速移动。
  • CI构建 为团队创建一个共享的源真实性。
  • 调试和发布版本 定义应用程序如何编译和配置
  • 发行版本 定义谁接收应用程序以及如何接收
  • 签名版本 确定平台是否会信任 artifact
  • 基于频道的更新 确定更改如何在安装后移动

这些并不是竞争分类。它们叠加

“阶段构建”通常是一个组合而非单一事物。它通常是风味、环境、签名和发行选择的组合

这就是为什么两个团队都可以说“我们需要一个beta版本”并且意味着完全不同的artifact

这在移动设备上尤其重要,因为每一步都会增加摩擦力。原生编译、机密、授权、应用商店跟踪、测试者访问、环境配置和回滚都需要齐头并进。如果其中一个部分松动,发布过程就会变成一种部落知识。然后,一位工程师去度假, nobody就无法顺利发布了

那些处理得好的团队,不会记住更多的脚本。他们将构建类型定义为质量门控。每个门控降低了不同类型的风险:code破损、配置错误、签名错误、发布错误或恢复错误。

构建谱系:本地构建与CI构建

本地构建是你为自己制作的版本。团队可以信任的构建版本是CI构建。

这听起来很明显,但很多构建痛苦是因为团队把这两者混淆起来。有人证明‘它在我的机器上工作了’,然后分支在CI中失败,因为本地环境隐式依赖于缓存的依赖项、手动编辑的文件或签名资产从未进入自动化。

专注的男子在现代办公室的笔记本电脑上工作,研究本地与CI开发。

本地构建

本地构建是私有的、快速的、可丢弃的。您使用它们来回答紧急问题。

可以屏幕渲染吗?原生插件是否初始化?Gradle或Xcode更改是否破坏了编译?您是否可以使用日志调试重现崩溃?

一个好的本地构建优先考虑速度而不是形式。它经常包括松散的检查、冗长的日志、开发人员开关和临时的仪器。那样是可以的。它的工作是快速反馈。

什么不起作用的是将本地构建提升到比它更重要的东西。一个本地构建永远 shouldn’t 成为发布artifact,因为它在一台笔记本电脑上编译成功了。

CI构建

CI构建会因为一个原因而更慢。它们从个人机器状态中移除并使构建过程可重复。

当CI健康时,它会做三件事很好:

  • 从头开始重建: 它证明了项目可以在没有隐含的本地假设的情况下编译。
  • 运行团队级别的检查: 单元测试、linting 和打包规则每次都发生在同一个地方。
  • 产生可追踪的工件: 团队可以将构建与提交、branch 和 pipeline 运行关联起来。

这就是为什么我喜欢工作室与工厂的类比。您的笔记本电脑是您迭代的工作台。CI 是证明过程是真实的工厂流水线。

如果您的团队仍然手动决定哪个脚本在哪里运行,请将该逻辑集中在自动化中。一个实际参考是关于使用__CAPGO_KEEP_0__ Actions管理开发和生产构建的指南。 managing dev and prod builds with GitHub Actions.

CI构建会因为一个原因而更慢。它们从个人机器状态中移除并使构建过程可重复。 如果QA、产品或支持需要artifact,它应该来自CI,而不是开发人员的机器。

一旦你接受了这一点,构建生命周期的其余部分就变得容易了。选择口味、签名、环境注入和分发都应该在任何团队成员都可以检查的管道中。

核心构建口味:Debug vs Release

构建有很多标签,但在所有这些命名之下,通常最重要的两种口味是: debugrelease.

它们存在于开发人员和终端用户需要相反的东西。

用于帮助人类检查行为的debug构建。它通常保留更多的元数据,方便调试,避免了可以隐藏问题的激进优化。

有一个来自建筑规范的有用的类比。规范通常分为

Debug构建

Release构建 debug模式, 优化模式, 专有模式, 和 参考标准模式 类型, 和一个调试构建映射得很好到一个 debug模式 方法 优化模式 方法 着重于所需结果, 如本构建规范类型的分解所述.

在实践中, 调试构建是您想要像这样的事情:

  • 可读性诊断: 堆栈跟踪、控制台输出和符号,帮助您找到错误。
  • 开发者便利性: 模拟开关、测试菜单和特性switches,适合于非终端用户。
  • 低摩擦迭代: 更快的安装和运行周期比打磨的包更重要。

调试构建不是“坏的”。它们是为特定目的而设计的。

发布构建

发布构建是为野外设备而设计的。这会立即改变优先级。

现在您关心的是包的完整性、启动行为、更紧密的安全姿势、更小的负载和可预测的运行时特性。您还希望减少意外的入口点以便于检查或滥用。

交易的简单之处在于:调试构建更容易检查的所有内容都倾向于使发布构建不适合生产。

我与团队使用的决策边界是:

风味 适合 优化
调试 开发、本地测试、问题复现 可见性和迭代速度
发布 beta 分发、商店提交、生产发布 稳定性、性能和信任

团队为什么仍然会这样错误

混淆的最大来源是将“环境”与“风味”混淆。

一个构建可以 release flavor pointed at staging services。这种情况在QA测试中很常见,因为你希望生产环境的行为与非生产环境的数据结合。一个构建也可以是 debug flavor pointed at development services 用于日常编码。这些是不同的维度

A lot of script sprawl originates from teams encoding every possible combination in package names instead of documenting the matrix

在非开发人员测试用户界面行为时,始终将release flavor发射。将debug flavor保留用于工程工作和故意的故障排除

这一个规则消除了很多意外的复杂性

Mapping Builds to Distribution Environments

关于构建类型的讨论通常会停得太早。它们解释了本地、调试和发布,然后忽略了更困难的问题:这个构建要去哪里?

这个目的地会改变构建应该包含什么、如何签名以及谁应该接收它

一个实际的构建工作流通常会通过几个环境,各有不同的受众和风险承受能力。如果你正在开发Capacitor应用,它也会有助于保持开发和生产应用行为之间的清晰分离 在Capacitor中因为很多“构建错误”实际上是环境映射错误。

夜间和金凤花

这些是早期警告构建。它们是为工程师、QA或愿意忍受粗糙边缘的小型内部团队准备的。

夜间构建通常在定期或从最新的主分支状态生成。金凤花构建是故意向狭窄的观众暴露的,之后才会进行更广泛的推广。我把它们视为学习工具,而不是稳定性的承诺。

它们在以下情况下很有用:

  • 分支是否在模块之间整合得很好?
  • 原生依赖升级是否破坏了特定设备家族?
  • 内部测试者是否能在更广泛的beta暴露之前发现回归?

什么不起作用的是给予金凤花构建的人们,期待着精致的软件。您会得到噪音的反馈,错误的观众会把正常的更迭称为发布问题。

测试和beta

到这个阶段,产品质量比工程便利性更重要。

测试或beta构建应该感觉像真正用户会得到的那样。通常意味着发布风格、生产样式的配置以及通过平台工具如TestFlight或Google Play测试轨道进行控制的分发。

这里的受众发生了变化:

  • QA 验证回归测试、工作流程和验收标准。
  • 产品经理在一个模拟的 shell 中审查行为。
  • 外部测试者验证可用性、设备覆盖和边缘案例。
  • 支持或成功团队可能会预览即将到来的更改。

这里的错误是把 beta 当作“只是另一个调试构建”。如果您的测试者正在评估真实用户流程,他们需要像发布一样的条件。

私有分发构建

有些应用需要构建从来不会到达公众商店受众的构建,或者需要先到达一个更窄的群体。

这包括客户专属构建、内部员工应用、受管制的工作流程、现场操作工具和企业专属分发。这些通常需要更严格的控制谁可以安装应用以及哪个后端。

这也是命名变得危险的地方。团队经常说“企业构建”时实际上意味着几种不同的东西:

  • 一个私有签名的内部应用
  • 一个在商店分发的应用,但具有内部访问控制
  • 客户定制的品牌物品
  • 供投资者审阅的预发布候选版本

它们是不同的运营模型。请在管道和命名中将它们保持分开。

生产

生产构建是对公众的承诺。它们将发布到应用商店、Google Play商店或您的用户的等效批准渠道。

到这个阶段,构建应该是乏味的。这是赞扬。

您希望生产构建是可复现的、正确签名的、在发布条件下测试过的,并且与回滚计划相关联的。您不希望最后一分钟的手动编辑、机器特定的hack或“我们将在下一个构建中修复它”的妥协。

这里是快速查看版。

软件构建类型及其特征

构建类型 受众 上下文: 企业产品/定价页面。角色: UI标签。消息键 `enterprise_audience_label` (企业受众标签)。 发布方式
本地开发者 个人开发者 通常用于调试,快速迭代,设置本地环境 直接从本地机器安装
CI 验证 工程团队 可重复的自动化构建,共享检查 CI 构建存储
晚间或 Canary 内部测试者,选定的团队成员 早期集成状态,有限的发布 内部发布工具
测试或beta QA、产品、外部测试者 通常是发布类似的非公开环境映射 TestFlight、Play测试轨道、私有链接
即时或企业 内部员工、客户、受限组 受控配置、目的地特定签名 私有分发渠道
生产 公众用户 最终发布配置、商店准备签名 App Store 或 Google Play

选择合适的构建类型是匹配目标受众风险承受能力的关键。 大多数发布错误都是因为团队忽略了这一对齐。

The Critical Role of Code Signing

一个构建文件本身在移动设备上并不意味着什么。 平台需要证明它来自可信的来源,并且在创建后没有被修改过。 这个证明是 code signing.

如果您曾经有过一个编译完美但拒绝安装、上传或启动的构建,签名很可能是问题所在。

A computer screen displaying Python source code for Blender with a Code Signing overlay text.

签名实际上证明了什么

For a mobile team, code signing does three jobs.

  • 真实性: 它将应用程序与开发者或组织绑定起来。
  • 完整性: 它有助于证明自签名以来,艺术品没有被篡改。
  • 授权: 尤其是在苹果平台上,它还控制了应用程序在哪里和如何运行。

第三点就是让许多开发者感到困惑的原因。签名不仅仅是身份认证,还包括权限。

因此,同一个应用程序code可能需要根据是否希望在设备上本地运行、向测试者分发、内部部署还是提交到商店而使用不同的签名材料。

签名如何根据目的地而变化

这是保持整个过程清晰的思维模型: 签名遵循分发.

开发者在本地安装使用一个身份和权限集。通过TestFlight发送的beta版本使用另一个。内部分发路径可能需要不同的配置文件。公众商店发布有其自己的签名期望和审查兼容的打包。

因此,“重新签名”通常不是一个小要求。签名一旦改变,允许的目的地也可能会随之改变。

通常情况下,严格的设置包括:

  • 在CI中存储签名资产: 不在个人笔记本上。
  • 清晰的分离方式: 开发、内部测试、企业、商店发布。
  • 轮换和访问控制: 尤其是在承包商或多个产品团队共享基础设施时。
  • 可审计性: 您需要知道哪个管道使用了哪个签名身份。

如果您的团队在Capacitor应用内部发布Web更新,那么还有一个签名层需要考虑。这篇关于Capacitor更新器__CAPGO_KEEP_1__签名的端到端安全概述 end-to-end security for Capacitor updater code signing 签名问题通常不是来自加密。它们来自于不明确的所有权、手动处理和无法显示哪个身份被应用的构建管道。

将签名材料视为生产基础设施,因为这就是它的本质。

__CAPGO_KEEP_0__

使用 CI/CD 和更新频道协调发布

当团队成熟时,挑战不在于了解构建类型,而在于在不依赖人类猜测的情况下协调它们。

这项协调工作应该在 CI/CD 中进行。

截图来自 https://capgo.app

您的管道是构建契约

可靠的管道每次都应该回答以下问题:

  • 这个构建是用来做什么的
  • 它使用哪种风味
  • 它接收哪些环境变量
  • 它必须通过哪些测试
  • 哪个签名身份适用
  • 构建产物将被送往哪里

该结构反映了一个好的技术规范。一个良好的规范应该包括 目的和范围、功能需求、设计需求、技术标准、测试需求、交付需求和支持或维护需求,如本技术规范指南 中所述。这种同样的纪律使CI/CD更容易理解,因为管道不再是一个脚本的袋子,而是一个可执行的发布政策在实践中,管道应该决定,而不是由手动运行它的工程师决定。branch规则、标签、审批步骤、签名上下文和部署目标都应该被编码

什么有效

branch驱动意图

  • 主分支、发布分支和标签触发不同的工作流 明确的工件命名
  • 风味、环境和目标在输出中可见 推广而不是重建手动
  • __CAPGO_KEEP_0__ 移动验证的艺术品而不是重新创建它们。

人们总是失败的方法是“一份灵活的脚本”方法,希望每个人都能通过自定义标志来匹配商店或测试者需要的内容。

频道可以在二进制文件发布后添加控制。

原生构建仍然粗糙。一旦发布到商店中,改变Capacitor应用中的网页内容并不总是需要重新构建整个二进制文件。

这就是更新频道变得有用的地方。它们让团队可以针对已安装的生产二进制文件中的特定用户推送网页资产更新。对于Capacitor团队来说,一种选择是 Capgo发布到目标频道的签名网包,使您可以在每次构建原生壳时都推送JavaScript、CSS、复制、配置和资产更改。

一个实际的模式如下:

  • CI/CD中的二进制构建: 创建、签名和分发原生应用。
  • 频道分配: 将用户或环境映射到beta、staging、production或客户特定流中。
  • 选择性发布: 将网页变化发送到一个小组,避免更广泛的曝光。
  • 回滚路径: 在等待商店审查之前,禁用或回滚一个坏的更新。

如果您还没有设置该模型,请参阅以下教程,了解如何在__CAPGO_KEEP_0__中创建和删除更新通道。 creating and deleting update channels in Capacitor 这是许多移动团队需要的战略转变。构建类型不仅仅是艺术品。它们是控制点。CI/CD控制如何生成二进制文件。通道控制如何发布安装后更改。

现代构建工作流的最佳实践

一个理智的构建系统是有主见的。它不会让每个开发人员自行决定发布行为。

我曾经工作过的最强大的设置共享了几个习惯:

最佳实践

构建类型

  • 分离明确的轴线: 味道、环境、签名目标和分发目标不应混杂在一起的模糊标签。
  • 让CI生成团队可用的工件: 本地构建是用于开发,而不是用于投资者信任。
  • 尽早在发布条件下测试: QA和beta测试者应该看到与实际应用行为尽可能接近的行为。
  • 将签名资产从笔记本电脑中分离出来: 机密信息应在受控的基础设施中具有有限访问权限。
  • 以人类可读的方式命名工件: 如果有人在几秒钟内无法识别一个文件的用途,则命名不佳。
  • 优先考虑推进而不是重建: 一旦工件被验证,应将其通过工作流程推进,而不是手动重建。
  • 设计回滚之前: 商店回滚很慢,操作性很重。 Web层回滚可以在 Capacitor 更新时更快,但前提是你必须先规划好渠道和政策。

最大的思维转变是:不要问“哪个构建脚本应该运行?”而是问“我在这个阶段管理的风险是什么?”这个问题会产生更好的构建系统。

如果你的工作流程清晰地回答了这个问题,那么你的发布过程就变得更容易操作,更容易审计,并且对一位资深工程师记住正确的咒语的依赖性就减少了。


如果你的团队部署 Capacitor 应用,并且想要更紧密地控制发布工作流程, Capgo 是值得评估的一部分栈。它处理针对 Capacitor 应用内的 Web 资产的实时更新,支持签名的捆绑包,基于渠道的发布,和回滚控制,这使得它在你需要更快的修复而不替换原生构建管道时非常有用。

Capacitor 应用程序的即时更新

When a web-layer bug is live, ship the fix through Capgo instead of waiting days for app store approval. Users get the update in the background while native changes stay in the normal review path.

Martin 为您提供人性化的支持

立即开始

最新博客

Capgo 为您提供创建真正专业的移动应用所需的最佳见解