PaceVer:面向移动应用的SemVer替代方案
摘要
PaceVer 是一种面向移动应用的版本管理方案,它区分了原生二进制发布和空中更新,使用 MARKETING、NATIVE 和 OTA 组件来反映变更如何到达用户。
<p>我刚刚发布了这个。如有任何问题,欢迎提问,我会尽力回答!这是我一段时间以来非正式地采用的做法,所以我决定让其更正式化,以便他人查看/使用。</p>
<p><a href="https://lobste.rs/s/b4fy6z/pacever_alternative_semver_for_mobile">评论</a></p>
查看缓存全文
缓存时间: 2026/06/02 21:37
# PaceVer — 节奏版本控制
来源:https://pacever.org/
## 概述 (https://pacever.org/#summary)
版本号采用`MARKETING\.NATIVE\.OTA`的形式:
``
1 . 4 . 12
│ │ │
│ │ └─ OTA 每次空中更新时递增 (快速)
│ └───────── NATIVE 每次新商店二进制时递增 (慢速)
└───────────────── MARKETING 由你定义:时代、年份、重新设计、或永不变化
``
- **MARKETING**:自由数字。用于重新设计、新年、品牌重塑、重写、里程碑,或永不变化。它不携带兼容性承诺。如果你关心传达变更的*规模*,这是唯一承载的地方。`0`保留给预发布阶段;将第一个稳定版本发布为`1\.0\.0`,然后继续。
- **NATIVE**:当发布需要从商店**安装新二进制**时递增(任何OTA无法交付的内容:原生代码、新依赖、SDK/运行时升级、权限变更)。缓慢:受限于商店审核。将OTA重置为0。
- **OTA**:每次通过**空中推送**到已有构建的发布(JavaScript、样式、内容、当前运行时内的资源)时递增。快速:几分钟内到达,无需商店审核。
新的原生构建始终将OTA重置为`0`。默认情况下,MARKETING递增也会重置NATIVE和OTA,因此一次重新设计会变为`2\.0\.0`;团队也可以让数字继续攀升至`2\.6\.2`(参见常见问题)。选择一种约定并保持一致。
## 引言 (https://pacever.org/#introduction)
移动应用的发布方式与库不同。库有一个发布渠道和一个关键问题:*接口是否破坏?*这就是语义化版本控制回答的问题,而且回答得很好。
通过 React Native、Expo 或类似框架发布的应用拥有**两个**发布渠道,以**两种速度**移动。某些变更(新原生模块、SDK 升级、新权限)只能通过分发渠道(App Store、Play Store、TestFlight、企业/MDM)以新二进制形式到达用户:缓慢、受限于重新分发、无法立即回滚。其他变更(文案修复、界面重样式、纯JS功能)可以通过空中推送在几分钟内独立到达设备,无需商店审核。
SemVer 无法看到这一点。它的`MAJOR\.MINOR\.PATCH`描述*变更了什么*;它没有说明*变更如何到达用户*,而在移动端,这恰恰是决定审核延迟、发布速度和回滚能力的关键因素。PaceVer 将这个事实作为版本。
PaceVer 故意不说明变更的大小。一个单词的修复和整个屏幕的重写都递增 OTA 一次,因为它们以相同的方式、相同的节奏发布。如果你的团队希望表明某次发布是大事,那么这个信号放在 MARKETING 中,你可以随意使用。
## PaceVer 规范 (https://pacever.org/#spec)
关键词 “MUST”、“MUST NOT”、“SHOULD”、“SHOULD NOT” 和 “MAY” 应按照RFC 2119 (https://www.rfc-editor.org/rfc/rfc2119) 中的描述进行解释。
1. 使用 PaceVer 的项目必须区分两种发布:**原生发布**,需要通过分发渠道(App Store、Play Store、TestFlight、企业/MDM 或等效渠道)安装新二进制;**OTA 发布**,无需重新分发给已安装的二进制。
2. 正常版本号必须采用`X\.Y\.Z`形式,其中`X`(MARKETING)、`Y`(NATIVE)和`Z`(OTA)是非负整数,且不得包含前导零。每个后续版本必须按规则 10 定义的优先级递增。各个元素不必逐次递增:递增一个元素会将其右侧的元素重置(规则 6),因此整个版本始终向前排序,即使重置元素降至`0`。
3. **MARKETING**(`X`)保留为`0`表示应用处于预发布状态,尚未被视为稳定或向公众发布。一旦 MARKETING 达到`1`或更高,递增的*原因*和*规模*不携带任何强制含义或兼容性承诺:团队可以出于任何原因递增(新年、重新设计、品牌重塑、重写、里程碑、变更规模),或者永远不再递增。它唯一固定的约束是方向:在整个项目生命周期中,MARKETING 必须单调非递减。
4. **NATIVE**(`Y`)必须在一项发布需要安装新二进制时递增,即任何无法通过空中交付的变更。这包括但不限于:原生代码或原生依赖变更、运行时或 SDK 升级、权限或授权变更,以及已编译的应用配置变更。
5. **OTA**(`Z`)必须为每次通过空中交付给现有原生构建的发布而递增,即任何无需新二进制即可交付的变更,例如当前原生运行时内的 JavaScript、样式、内容和资源。
6. 当 NATIVE 递增时,OTA 必须重置为`0`,因为新的原生构建开始一个新的 OTA 血统。当 MARKETING 递增时,NATIVE 和 OTA 应重置为`0`;这是推荐的默认做法。项目也可以让 NATIVE 和 OTA 在 MARKETING 提升时继续攀升(参见常见问题),但必须选择一种约定并始终如一地应用。
7. 新安装的原生构建,在应用任何 OTA 发布之前,其 OTA 为`0`。原生构建内捆绑的 JavaScript 和资源是其**基线**,而非 OTA 发布,不得计为 OTA`1`。
8. 构建报告的版本应在运行时组成:MARKETING 和 NATIVE 由安装的二进制固定;OTA 反映当前应用的空中发布,如果未应用则为`0`。
9. OTA 发布必须与它目标的原生构建兼容,并且不得发送给非为其生产的原生构建。(在 Expo/EAS 术语中,OTA 发布限定为匹配的运行时版本。)
10. **优先级**通过比较 MARKETING,然后 NATIVE,然后 OTA 的数字来确定(`1\.2\.0 < 1\.2\.7 < 1\.3\.0 < 2\.0\.0`)。
11. **单一版本线,所有平台同步。** MARKETING、NATIVE 和 OTA 是单个项目范围的数字,**不是**按平台追踪。当 NATIVE 递增时,必须向应用分发的每个原生分发渠道(App Store、Play Store 等)发布新二进制,即使某个平台没有功能变更,以确保所有平台共享相同的 NATIVE 构建。这使每个平台保持在公共运行时上,因此单个 OTA 发布可以在一个 OTA 编号下适用于所有平台。因此平台永远不会出现分歧:整个应用始终只有一个当前版本。
12. **范围。** PaceVer 适用于通过原生渠道和 OTA 渠道分发的面向用户的应用程序客户端。它**不**适用于向其他软件公开程序化接口的库、包或 API。请使用 SemVer 为那些软件进行版本控制。
13. 标识符可以追加在 OTA 之后:连字符引入预发布标识符(例如`1\.4\.0\-rc\.1`),加号引入构建元数据(例如`1\.4\.0\+ios`)。PaceVer 不赋予这些后缀任何渠道或节奏含义;其解释留给团队。在确定优先级时,构建元数据必须被忽略。
14. **初始版本和达到稳定。** 项目应从`0\.1\.0`开始,其中 MARKETING`0`标记预发布阶段。NATIVE 和 OTA 在`0\.x`阶段照常递增。当团队认为应用稳定且准备向公众发布时,将 MARKETING 递增至`1`。按照推荐的重新设置(规则 6),第一个稳定版本是`1\.0\.0`;不重新设置的团队会继续使用其运行中的数字,因此`0\.5\.3`变为`1\.5\.3`。达到稳定的确切时刻由团队决定。
## 为什么使用 PaceVer (https://pacever.org/#why)
- **数字告诉你节奏。** `2\.5\.0 → 2\.5\.3`通过空中发布,已经到达设备。`2\.5\.3 → 2\.6\.0`是等待商店审核的新二进制。你一眼就能看出部署故事。
- **它免费符合商店规则。** 二进制携带`MARKETING\.NATIVE\.0`作为营销版本(商店期望的三个整数,OTA 固定为`0`作为基线);实时的 OTA 数字在运行时在其上组合。
- **它在形式上仍与 SemVer 兼容。** PaceVer 版本仍然是`X\.Y\.Z`字符串,按与 SemVer 相同的从左到右优先级排序,因此对 SemVer 形状版本进行排序或比较的工具仍然有效。PaceVer 改变了三个位置*的含义*,而不是格式或排序。
- **它结束了 MAJOR 争论。** 不再争论一次重新设计是否“值得”一次主版本递增。MARKETING 是一个自由数字,你可以指向你的团队关心的任何事物。
- **它与你已经使用的工具匹配。** NATIVE 与你的二进制/运行时版本对齐;OTA 与你的更新渠道(EAS Update、CodePush)对齐。
## 何时不应使用 PaceVer (https://pacever.org/#when-not)
PaceVer 适用于通过原生渠道和 OTA 渠道分发的面向用户的应用程序客户端(规则 12)。当以下情况时,它是错误的工具:
- **你在对库、包或 API 进行版本控制。** 任何向其他软件公开程序化接口的内容应使用 SemVer,其全部工作就是指示兼容性。PaceVer 不说明兼容性。
- **你的应用实际上只有一个交付渠道。** 网络应用或 PWA 每次部署都通过相同方式,没有 PaceVer 要捕捉的原生/OTA 分离。请按自身条件进行版本控制。
- **你的受众关注的是最新程度或规模。** 如果版本号的读者主要想要“多新”(CalVer)或“多大”(SemVer MAJOR)而不是“哪个渠道”,PaceVer 将信号放错了位置。
采用 PaceVer 意味着放弃 SemVer 的兼容性契约和 CalVer 的一目了然的新旧程度,以换取一目了然的*节奏*信号。请有意地做出这个权衡。
## 示例:一个应用的版本历史 (https://pacever.org/#example)
版本渠道所交付内容`0\.1\.0`NATIVE首次构建。预发布阶段开始。`0\.1\.1`OTABeta 文案调整,空中推送。`0\.2\.0`NATIVE添加相机模块,给测试人员的新二进制,OTA 重置。`1\.0\.0`NATIVE在 App Store 和 Play Store 上首次公开发布。MARKETING → 1,所有内容重置。`1\.0\.1`OTA拼写修复,几分钟内到达设备。`1\.0\.2`OTAJavaScript 崩溃修复。`1\.1\.0`NATIVEExpo SDK 升级,向两个商店发布新二进制,OTA 重置。`1\.1\.1`OTA重新设计了一个屏幕。`2\.0\.0`NATIVE团队希望标记的全面季节性重新设计。MARKETING 递增,向两个商店发布新二进制,所有内容重置。每一行仅从数字就告诉你它是如何发布的:中间数字变更意味着经过商店;最后数字变更意味着它已经几分钟内到达设备。
## 常见问题 (https://pacever.org/#faq)
### OTA 数字物理上在哪里?
不在二进制的商店版本中。OTA 更新无法重写它,这没问题。应用在运行时组合其版本:它从二进制读取 MARKETING 和 NATIVE,从已应用更新的清单(例如 Expo 中的`Updates\.manifest`/`extra`)读取 OTA。没有应用更新的全新安装报告 OTA`0`。
### 更高的 OTA 数字意味着更大的变更吗?
不。OTA 计数的是空中*发布*,而不是它们的规模。一个拼写修复和一个新屏幕都递增 OTA 一次。如果你关心规模,请使用 MARKETING 数字来指示。
### 递增 MARKETING 会将 NATIVE 和 OTA 重置为零吗?
默认情况下,是的。MARKETING 递增变为`X\.0\.0`,就像 NATIVE 递增重置 OTA 一样,因此从`1\.6\.2`开始的重新设计会落在`2\.0\.0`上。这是推荐的约定,但在 MARKETING 递增时重置并非强制;请参见下一个问题。
### 我可以跳过重置,让数字继续攀升吗?
可以。你可以不重置,而是让 MARKETING 作为一个纯标签浮动,而 NATIVE 和 OTA 继续攀升,因此`1\.6\.2`变为`2\.6\.2`而不是`2\.0\.0`。权衡:你失去了干净的`X\.0\.0`时代边界,但你在整个应用生命周期中保持了一个单一单调的原生和 OTA 计数,一些团队觉得这更容易推理。无论哪种方式,优先级仍然有效,因为版本从左到右比较。无论选择哪种,请始终一致地应用它。(新的 NATIVE 构建始终重置 OTA;该部分不是可选的,因为新二进制开始一个新的 OTA 血统。)
### 我可以通过空中更新来递增 MARKETING 或 NATIVE 吗?
不。MARKETING 和 NATIVE 位于已安装的二进制中(规则 8),因此更改其中任何一个都意味着发布新的原生构建。只有 OTA 可以在没有新二进制的情况下移动,这就是为什么 MARKETING 或 NATIVE 变更总是以 OTA 回到`0`而落地。
### 我可以回滚原生发布吗?
不,这是有意为之:与应用商店本身一样,PaceVer 没有原生回滚的概念。NATIVE 只能向前移动(规则 2 的优先级),并且 OTA 发布限定于为其生产的原生构建(规则 9),因此你无法将用户退回到先前二进制的 OTA 血统。要从糟糕的原生构建中恢复,你以新的 NATIVE 编号重新发布先前良好构建的内容,例如将原本是 NATIVE 5 的内容再次作为 NATIVE 7 发布,然后继续。相比之下,OTA 可以在同一个原生构建内进行回滚,速度与其发布一样快。
### 原生变更只影响 iOS。我必须也发布 Android 吗?
是的,这是有意为之。NATIVE 递增会向*每个*平台发布新二进制,即使某个平台没有功能变更,以使所有平台保持在同一 NATIVE 构建上。这是为了 OTA 的利益:OTA 发布限定于运行时,因此让每个平台保持在公共运行时上,可以让一个 OTA 发布在单个 OTA 编号下适用于所有平台。看起来多余的 Android 构建通常也不是空白的:递增 NATIVE 会递增运行时,因此它是真正的新二进制,只是没有功能变更。代价是多一次商店提交;回报是整个应用有一个连贯的版本线。
### 我的应用也在网络上。那里没有原生构建。
PaceVer 不涵盖网络。网络(和 PWA)实际上只有一个渠道(每次部署都是空中推送),因此原生/OTA 分离不适用。请按自身条件对网络进行版本控制。
### 我可以为我的库或后端 API 使用 PaceVer 吗?
不。使用 SemVer。PaceVer 不说明 API 兼容性,而那是库版本控制的全部意义。PaceVer 用于发布应用,而不是契约。
### 为什么 PaceVer 不用 PaceVer 进行版本控制?
因为 PaceVer 用于应用,而这是一个文档。规范没有原生构建,也没有空中渠道。它有一个别人依赖的契约,这正是范围规则中说要用 SemVer 进行版本控制的情况。所以 PaceVer 遵守自己的规则,以 SemVer 形式发布。SemVer 对自身进行版本控制;PaceVer 用 SemVer 对自身进行版本控制。各司其职。
### 关于第一个发布呢?
从`0\.1\.0`开始。MARKETING`0`是预发布阶段,你通过`0\.x`构建直到应用准备就绪。当应用准备好向公众发布时,将 MARKETING 递增至`1`。按照推荐的重新设置,这会落在`1\.0\.0`上;如果你不重置,你会将运行中的数字带到`1\.y\.z`。推荐的路径就是`0\.1\.0 → 1\.0\.0 →`继续。确切时刻并不重要;这是一个当感觉正确时升起的旗帜。
### 我已经在 SemVer 下发布。如何迁移?
不要向下重置。App Store 和 Play Store 拒绝降低营销版本,因此已经处于例如`3\.4\.1`的应用不能通过从`1\.0\.0`重新开始来采用 PaceVer。因为 MARKETING 是一个自由的、单调非递减的数字,请保持你当前的前导数字作为 MARKETING,并从当前位置开始应用 PaceVer 的 NATIVE 和 OTA 语义。`0\.1\.0`起始和重置规则适用于新项目;现有应用将其历史向前推进。
## 关于 (https://pacever.org/#about)
PaceVer 是由...
相似文章
PACE:自进化代理的任意有效验收测试
PACE 为自进化代理引入了一种任意有效的提交门,它用序贯假设检验替代贪婪接受,控制错误提交概率,减少震荡,同时保持性能且方差更低。
@PrajwalTomar_:我用这套技术栈把 PACT(@ignytstudio 第一款移动应用)做到盈利
开发者公开社交闹钟 App「PACT」技术栈:AI 验证、实时推送、应用内支付,全部用 Swift 原生开发。
MoDev
MoDev 是一个专为移动设备设计的AI开发环境。
@AdinaYakup: MiniCPM V4.6 一个真正能在手机上运行的 1B 多模态大语言模型,由 @OpenBMB 刚刚发布 1B - Apache2.0 支持 iOS、Android,…
OpenBMB 发布了 MiniCPM V4.6,这是一个专为移动设备优化的 1B 参数多模态大语言模型,采用 Apache 2.0 许可证。它具备混合视觉 token 压缩功能,声称在 iOS、Android 和 HarmonyOS 上原生运行时,吞吐量比 Qwen3.5 0.8B 快约 1.5 倍。
Open Vibe
Open Vibe 是一款新产品,旨在帮助开发者在集成 AI 的同时顺利发布 SaaS 应用,避免常见的开发瓶颈。