跳过主要内容

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

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

马丁·多纳迪厄

马丁·多纳迪厄

简化中文市场专家

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

你打开一个项目,看到 build:ios:dev, build:android:qa, build:staging, build:release, build:prod,再加上几个不想碰的shell脚本。然后有人说,“请在今天晚上为客户准备一个测试环境构建。”如果你是中级移动开发者,这个请求通常会感到很不明确。哪个配置?哪个签名身份?哪个后端?哪个分发路径?

这种混乱通常来自于将构建类型视为平面列表。它们并不是。它们是一种工作流程。每个构建都旨在解决特定问题,在特定点之间解决你的笔记本电脑和用户设备之间的问题。

一个构建不仅仅是一个编译好的应用。它是一个为特定目的、特定人群和特定环境而组装的应用版本。一些构建存在于帮助你调试。一些存在于帮助QA安全地破坏东西。一些存在于使发布工程师能够产生可信的工件。一些存在于使产品团队能够以更少风险的方式交付变化。

如果你的本地环境设置仍然感到不稳定,之前的所有事情都没有开始之前,首先使用一个合适的 Capacitor 本地环境设置。构建复杂性变得更容易理解,当你的基础工具是可预测的时。

目录

软件构建的世界

我经常看到的最常见的错误是假设构建名称包含了所有信息。它们并没有。 staging 这可能意味着“针对开发环境的发布版本”。在另一个仓库中,它可能意味着“可调试的QA artifact with mocked payments.”。在第三个仓库中,它可能意味着“私有发布的生产签名版”。

这就是为什么团队会感到混乱的原因。标签只有在您了解该构建正在执行的工作时才有用。

有一个有用的方法来思考构建类型:

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

它们并不是竞争的类别。它们是叠加的。

‘预发布构建’通常不是单一的东西。它通常是风味、环境、签名和发布选择的组合。

这就是为什么两个团队都可以说‘我们需要一个beta版本’,但却指的是完全不同的artifact。

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

处理这一点的团队不需要记住更多的脚本。他们将构建类型定义为质量门控。每个门控降低了不同的风险:破坏性code、错误的配置、错误的签名、错误的发布或错误的恢复。

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

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

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

专注的男子在现代办公室里工作着,研究本地构建与CI构建。

本地构建

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

屏幕是否能渲染?原生插件是否初始化?Gradle 或 Xcode 是否更改导致编译错误?是否能在日志开启的情况下复现崩溃?

一个好的本地构建优先考虑速度而不是形式。它通常包括松散的检查、冗长的日志、开发者开关和临时的仪器。没问题。它的工作是快速反馈。

问题在于将本地构建提升为比它更重要的东西。一个本地构建应该永远不会成为发布的artifact,因为它在一台笔记本上编译成功了。

CI 构建

CI 构建慢的原因是它从个人机器状态中移除了变量,并使构建过程可重复。

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

  • 从头重建: 它证明了项目可以编译而不依赖于本地的隐含假设。
  • 运行团队级别的检查: 单元测试、linting 和打包规则每次都发生在同一个地方。
  • 生成可追踪的artifact: 团队可以将构建与提交、分支和管道运行关联起来。

我喜欢工作坊与工厂的类比。你的笔记本电脑是迭代的工作台。CI是证明流程是真实的那条assembly line。

如果你的团队仍然手动决定哪个脚本在哪里运行,centralize那逻辑在自动化中。一个实用的参考是关于 使用GitHub Actions管理dev和prod builds的指南.

实用规则: 如果QA、产品或支持需要artifact,它应该来自CI,而不是来自开发人员的机器。

一旦你接受了这一点,整个build lifecycle就变得容易了。Flavor选择、签名、环境注入和分发都属于任何团队成员都可以检查的pipeline中。

核心build风味:Debug vs Release

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

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

一张比较调试版本和发布版本的图表,展示了性能和目的的关键区别。

调试版本

调试版本是为了帮助人类检查行为而设计的。它通常保留更多的元数据,方便调试,避免了激进的优化,这种优化可能会隐藏问题。

从建筑规范中可以找到一个有用的类比。规范通常分为 规范, 性能, 专有参考标准 类型,调试版本很好地映射到 规范 方法,因为它 dictate了exact的工具和方法来分析,而发布版本映射到一个 性能 这种方法专注于实现的结果,正如在 建筑规范类型的分解.

在实践中,调试版本是您希望看到的内容:

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

调试版本不是“差的”。它们是为特定目的而设计的。

发布版本

Release builds 是针对野外设备制作的。 这一变化立即改变了优先级。

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

这种权衡很简单。 Everything 使调试构建更容易检查的东西往往会使发布构建不适合生产环境。

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

口味 最佳选择 它优化
调试 开发、本地测试、问题复制 可见性和迭代速度
发布 beta 分发、商店提交、生产发布 __CAPGO_KEEP_0__

为什么团队仍然会这样做

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

一个构建可以是 指向测试环境的发布口味这是 QA 的常见做法,因为您希望在非生产环境中使用生产行为。一个构建也可以是 指向开发环境的调试口味 用于日常编码。这些是不同的轴。

团队编码每种可能 combination 的脚本导致了很多 script sprawl

而不是记录矩阵。

在非开发人员测试用户界面行为时,发布口味应随时发布。调试口味保留给工程工作和故意故错。

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

大多数关于构建类型的讨论都太过简单。它们解释了本地、调试和发布,然后忽略了更困难的问题:构建的目的地在哪里?

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

一个实际的构建工作流通常会通过几个环境,各自有不同的受众和风险承受能力。如果您正在开发Capacitor应用程序,保持开发和生产应用程序行为之间的清晰界限也很有帮助。 development and production app behavior in Capacitor晚间和试验鸽

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

晚间构建通常在预定的时间表或最新的主分支状态下生成。试验鸽构建是故意向狭窄受众暴露的,之后才会进行更广泛的推广。

我把它们视为学习工具,而不是稳定性的承诺。

它们在您需要回答的问题时很有用,如:

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

什么不起作用的是给那些期望软件精益求精的人提供 Canary 版本。您会得到噪音式反馈,错误的观众会将正常的轮换误认为是发布问题。

测试环境和预览版

在这个阶段,产品质量比工程方便更重要。

在发布前期,测试版或beta版应该尽可能接近真实用户的体验。通常意味着使用发布版本的口味,尽可能使用生产环境的配置,并通过平台工具,如TestFlight或Google Play测试轨道,进行控制的分发。

这里观众的焦点转移了

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

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

私有分发构建

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

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

这是命名也变得危险的地方。团队经常说“企业构建”,但实际上他们真正的意思是:

  • 一个私有签名的内部应用
  • 一个仅在内部控制访问的商店分发应用
  • 一个客户特定的品牌化工件
  • 一个用于评估利益相关者的预发布版本

这些是不同的运营模型。将它们分别放在管道和命名中。

生产

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

到这个时候,构建应该是乏味的。这是赞扬。

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

这是一个快速概览。

软件构建类型及其特征

构建类型 受众 配置 发布方式
本地开发者 个人开发者 通常是调试,快速迭代,局部环境设置 直接从本地机器安装
CI 验证 工程团队 可重复的自动化构建,共享检查 CI artifact存储
夜间或 Canary 内部测试者、选定的团队成员 早期集成状态、受限的发布 内部发布工具
测试或 beta QA、产品、外部测试者 通常发布类、非公开环境映射 TestFlight、Play测试跟踪、私有链接
即时或企业 内部员工、客户、受限组 受控配置、目的地特定签名 私有分发渠道
生产 公众用户 __CAPGO_KEEP_0__ 最终发布配置,存储签名 App Store 或 Google Play

正确的构建类型是匹配用户风险耐受度的类型。最常见的发布错误是团队忽略了这一对齐。

Code 签名的关键作用

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

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

一台显示 Python 源 code 的计算机屏幕,带有 Code 签名的覆盖文本。

签名实际上证明了什么

For a mobile team, code signing does three jobs.

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

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

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

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

这是保持过程理性的思维模型: 签名遵循分发.

A local developer install uses one set of identities and permissions. A beta build sent through TestFlight uses another. An internal distribution path may require different profiles again. A public store release has its own signing expectations and review-compatible packaging.

这就是为什么“重新签署构建”通常不是一个简单的要求。 一旦签名发生变化,构建的允许目的地也会随之改变。

A disciplined setup usually includes:

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

如果你的团队在Capacitor应用中发布Web更新,那么还有第二层签名需要考虑。 这个概述 end-to-end security for Capacitor updater code signing 这是有用的,因为它将原生二进制的信任与更新包的信任分开。

签名问题通常不是来自加密。它们来自不明确的所有权、手动处理和隐藏应用身份的构建管道。

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

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

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

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

截图来自 https://capgo.app

您的管道是构建合同

可靠的管道应该每次回答相同的问题:

  • 这个构建是为了什么
  • 它使用哪种口味
  • 哪些环境变量它接收
  • 哪些测试它必须通过
  • 哪个签名身份适用
  • 哪个位置 artifact 被送达

这结构反映了一个好的技术规范。一个良好的规范应该包括 目的和范围、功能需求、设计需求、技术标准、测试需求、交付需求和支持或维护需求如本 技术规范指南中所述。同样的纪律使 CI/CD 更容易理解,因为管道不再是一个脚本的袋子,而是一个可执行的发布政策。

在实践中,管道应该决定,而不是由手动运行的工程师决定。 branch 规则、标签、批准步骤、签名上下文和部署目标都应该被编码。

什么有效:

  • branch 驱动意图: main, release branches, and tags触发不同的工作流程。
  • 明确的工件命名: flavor,环境,和目标在输出中可见。
  • 推广而不是重建: 验证的工件向前移动,而不是根据需要重新创建它们。

什么经常会失败的是“一个灵活的脚本”方法,所有人都传递自定义标志并希望它们与商店或测试者需要的匹配。

通道添加控制后二进制发布

原生构建仍然粗粒度。一旦发布到商店,改变Capacitor应用中的Web内容并不总是需要一个新的二进制。

That’s where update channels become useful. They let teams target web asset updates to a subset of users inside an installed production binary. For Capacitor teams, one option is 对于Capgo团队,一个选项是__CAPGO_KEEP_0__

,它发布签名的Web包到目标通道,使您可以推送JavaScript、CSS、复制、配置和资产更改,而不必每次重建原生壳。

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

如果您尚未设置该模型,请参阅 关于在Capacitor中创建和删除更新通道的教程 使机制更加具体。

如果您尚未看到通道的动作,请参阅此简短演示:

很多移动团队都需要这种战略转变。

Build类型并不是简单的工件。

它们是控制点。

CI/CD控制如何生成二进制文件。

  • Channels控制如何暴露安装后更改。 最佳实践:现代构建工作流
  • 一个理智的构建系统是有主见的。 它不会让每个开发人员自行决定发布行为。
  • 我曾经工作过的最强大的设置共享了几个习惯: 分清各个轴:
  • flavor、环境、签名目标和分发目标不应混杂在一起。 让CI生成团队可用的工件:
  • 让人能读懂的命名文件: 如果有人在几秒钟内无法识别一个文件的用途,那么命名方式就不合适。
  • 优先考虑推广而不是重建: 一旦一个文件被验证,通过工作流程将其推进,而不是手动重建。
  • 在发布前设计回滚: 存储回滚是缓慢且操作性重的。 Web层回滚对于Capacitor更新可以更快,但只有你事先规划了通道和政策。

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

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


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

Capacitor 应用实时更新

当 web 层面 bug 活跃时,通过 Capgo 发布修复而不是等待几天的应用商店审批。用户在后台接收更新,而本机更改仍在正常审批路径中。

立即开始

最新博客文章

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