跳过主要内容

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

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

类型的构建简介:从本地到生产

你打开一个项目,看到 build:ios:dev, build:android:qa, build:staging, build:release, build:prod,还有几个shell脚本,没人想碰。然后有人说,“能否在今天晚些时候为客户准备一个测试构建?”如果你是中级移动开发者,那个请求通常会让你感到很恼火。哪个配置?哪个签名身份?哪个后端?哪个分发路径?”

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

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

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

目录

软件构建的世界

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

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

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

  • 本地构建 帮助个人开发者快速移动。
  • CI构建 为团队创建一个共享的源代码真相。
  • 调试和发布版本 定义应用程序如何编译和仪器化。
  • 分发构建 定义谁接收应用程序以及如何。
  • 签名构建 确定平台是否会信任该 artifact。
  • 基于频道的更新 这些不是竞争类别。它们叠加。

__CAPGO_KEEP_0__

A “staging build”通常不是单一的东西。它通常是风味、环境、签名和分发选择的组合。

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

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

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

构建谱系 本地构建vsCI构建

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

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

专注的男子在现代办公室里工作,专注于本地构建和CI开发的区别。

本地构建

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

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

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

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

CI 构建

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

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

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

为什么我喜欢工作室与工厂的类比。你的笔记本电脑是你迭代的地方。CI是证明流程是真实的那条assembly line。

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

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

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

核心构建风味 Debug vs Release

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

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

与debug版和release版的对比图表,展示了性能和目的的关键差异。

debug版

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

从建筑规范中可以找到一个有用的类比。规范通常分为 规范, 性能, 专有和 参考标准 类型,debug版与 规范 方法相对应,因为它 dictate了exact的工具和方法,而release版与 性能 以达到所需结果为目标的方法,正如在 关于建筑规范类型的分解中.

在实践中,调试构建是您希望看到的内容,如:

  • 可读的诊断信息: 堆栈跟踪、控制台输出和符号,帮助您找到错误。
  • 开发者便利: 模拟开关、测试菜单和功能开关,适合开发者但不适合普通用户。
  • 低摩擦迭代: 快速安装和运行的速度比打包的外观更重要。

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

发布构建

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

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

这种权衡很简单。使调试构建更容易检查的所有内容都倾向于使发布构建不适合生产。

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

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

为什么团队仍然会这样做

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

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

很多脚本杂乱起源于团队将每种可能的 combination 编码到包名中,而不是记录矩阵。

在非开发人员测试用户界面行为时,发布口味始终可以发布。调试口味保留给工程工作和故意的故障排除。

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

将构建映射到分发环境

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

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

一个实际的构建工作流通常会通过几个环境,每个环境都有不同的受众和风险承受能力。如果您正在开发Capacitor应用程序,它也会有助于在Capacitor中保持开发和生产应用程序行为之间的清晰界限,因为很多“构建错误”实际上是环境映射错误。 development and production app behavior in Capacitor这些是早期警告构建。它们是为工程师、QA或愿意承受粗糙边缘的小型内部团队准备的。

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

它们在回答以下问题时很有用:

分支是否在模块之间整洁地集成?

原生依赖升级是否破坏了特定设备家族?

  • 内部测试者是否能在更广泛的beta暴露之前发现回归?
  • __CAPGO_KEEP_0__
  • __CAPGO_KEEP_0__

什么不起作用的是给予 Canary 版本给期望软件精细化的人们。你会得到噪音的反馈,错误的观众会将正常的轮换问题归咎于发布问题。

发布阶段和测试阶段

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

一个发布阶段或测试阶段的构建应该感觉接近于真实用户会得到的东西。通常意味着发布版本的风格,可能的生产环境配置,以及通过平台工具如 TestFlight 或 Google Play 测试轨道进行控制的分发。

观众在这里发生了变化:

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

错误在于将测试阶段视为“只是另一个调试构建”。如果您的测试者正在评估真实的用户流程,他们需要发布版本的条件。

私有分发构建

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

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

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

  • 一个私人签名的内部应用
  • 一个仅在内部访问控制的商店分发应用
  • 一个客户专属的品牌化工件
  • 一个用于利益相关者审查的预发布发布候选人

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

生产

生产构建是公开承诺。它们将发送到应用商店、Google Play 商店或您的用户的等同认可渠道。

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

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

这是一个快速概览。

软件构建类型及其特征

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

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

Code签名的关键作用

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

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

一台电脑屏幕显示Python源code的Blender代码,带有Code签名的覆盖文本。

签名实际上证明了什么

对于移动团队来说,code签名有三个作用。

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

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

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

签名如何随着目的地而变化

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

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

因为这就是为什么“仅仅是放弃构建”通常不是一个小要求。 一旦签名发生变化, artifact允许的目的地也会随之改变。

一个严格的设置通常包括:

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

如果您的团队在一个Capacitor应用中发布网页更新,那么还有一个签名层需要考虑。这是一个关于 end-to-end安全性为Capacitor更新器code签名 __CAPGO_KEEP_1__签名对 updater 有用

因为它将原生二进制的信任与更新包的信任分开。

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

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

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

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

截图来自https://capgo.app

截图来自 https://__CAPGO_KEEP_0__.app

您的管道是构建合同

  • 可靠的管道应该每次回答相同的问题:
  • 这次构建是为了什么目的?
  • 哪些环境变量它接收到
  • 它必须通过哪些测试
  • 哪个签名身份适用
  • artifact 到哪里被交付

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

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

什么有效

  • branch驱动意图 main, release branches, 和 tags 触发不同的工作流程。
  • 显式 artifact 命名: flavor, 环境, 和目标在输出中可见。
  • 推广而不是重建: 将验证的 artifact 前进,而不是自行创建它们。

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

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

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

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

一个实用的模式如下:

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

如果您尚未设置该模型,请参阅以下教程以了解如何在__CAPGO_KEEP_0__中创建和删除更新频道。 创建和删除Capacitor中的更新频道 Binary build in CI/CD:

create, sign, and distribute the native app.

许多移动团队需要的战略转变就是这样。构建类型不仅仅是工件。它们是控制点。CI/CD控制如何生成二进制文件。频道控制如何暴露安装后更改。

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

理性的构建系统是有主见的。它不会让每个开发人员随意改动发布行为。

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

  • 分清各个维度: flavor、环境、签名目标和分发目标不应混杂在一起。
  • 让CI生成团队可用的工件: 本地构建是用于开发,而不是用于信托方的。
  • 尽早在发布条件下测试: QA和beta测试者应该看到的行为尽可能接近实际应用。
  • 将签名资产从笔记本电脑中分离出来: 机密信息应在受控的基础设施中具有有限访问权限。
  • 命名 artifact 以便人类可以阅读它们: 如果某人无法在几秒钟内识别一个文件的用途,那么命名方式就不够好。
  • 优先考虑推广而不是重建: 一旦 artifact 被验证,移动它通过工作流程而不是手动重建。
  • 在发布之前设计回滚: 存储回滚很慢,操作性很重。 Web层回滚可以在 Capacitor 更新中更快,但只有当您在前期规划了通道和政策时才会如此。

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

如果您的工作流程清晰回答这个问题,那么您的发布过程就会变得更容易操作、更容易审计,并且对一位经验丰富的工程师记住正确的咒语的依赖性会大大降低。


如果您的团队发布 Capacitor 应用程序并希望对发布工作流程有更紧密的控制权, Capgo 是值得作为该堆栈的一部分进行评估的。它处理 web 资产内 Capacitor 应用程序的目标 live 更新,支持签名的 bundle,基于通道的发布和回滚控制,这使得它在您需要更快的修复而不替换原生构建管道时非常有用。

Capacitor 应用程序的即时更新

当 web 层面的 bug 在 live 状态时,通过 Capgo 发布修复,而不是等待几天的 app store 审批。用户在后台接收更新,而原生变化仍然在正常的审批路径中。

来自 Martin 的人性化支持

立即开始

最新博客文章

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