4、SDK版本管理:语义化版本规范、版本号生成策略、Changelog编写规范、向后兼容性保证。

版本管理这事儿,说简单也简单,说复杂真能坑死人。我见过太多团队,版本号随便拍脑袋定,Changelog 全靠脑补,结果用户升级后一脸懵——「我到底该不该升这个版本?」

今天咱们就把 SDK 版本管理这件事彻底聊透。我会从语义化版本规范讲起,再到版本号怎么生成、Changelog 怎么写,最后聊聊向后兼容性这个老大难问题。

语义化版本规范:为什么是 X.Y.Z?

先问个问题:你见过 1.2.3.4 这种版本号吗?我见过。还有 v2019.08.15-beta2 这种。说实话,这种版本号除了让人头大,没有任何好处。

语义化版本规范(SemVer)的核心思想很简单:版本号要传达含义。格式就是 主版本号.次版本号.修订号,比如 2.1.3。

核心规则:

  • 主版本号:做了不兼容的 API 修改时递增
  • 次版本号:新增了向下兼容的功能时递增
  • 修订号:做了向下兼容的问题修复时递增

举个例子。你的 SDK 当前是 1.0.0。如果修复了一个 bug,变成 1.0.1。如果加了个新接口但没破坏旧的,变成 1.1.0。如果改了某个接口的签名,老代码跑不起来了,那就得 2.0.0。

我个人习惯在项目初期就把这个规范写进 README 里。别觉得多余,等用户来问「为什么 1.2.0 到 1.3.0 我的代码就编译不过了」的时候,你就知道规范有多重要了。

版本号生成策略:手动还是自动?

版本号怎么生成?这里分两种情况聊。

手动管理

小团队、内部 SDK,手动管理完全够用。我建议在项目根目录放一个 VERSION 文件,里面就一行数字:

1.2.3

然后 CI 脚本读这个文件,打 tag、生成包名。简单粗暴,但有效。

自动生成

大型项目或者多人协作的 SDK,手动管理容易出问题。我记得有一次,两个同事同时改了 VERSION 文件,结果一个版本号被覆盖了,发布出去的东西版本号对不上。那叫一个乱。

自动生成策略我推荐两种:

  • 基于 Git Tag:每次发布打 tag,CI 自动读取 tag 作为版本号。这是最稳妥的方式。
  • 基于 CI 构建号:比如 1.2.3.${BUILD_NUMBER},适合内部测试版本。

小技巧:预发布版本可以用 -alpha、-beta、-rc.1 这样的后缀。比如 2.0.0-alpha.1。这样用户知道这还是个预览版,别用到生产环境。

Changelog 编写规范:别让用户猜

Changelog 这东西,写好了是用户的好帮手,写不好就是废纸一张。我见过最离谱的 Changelog 就一句话:「修复了一些 bug,优化了性能」。你想想看,用户看到这个会怎么想?「到底修了啥?我该不该升?」

好的 Changelog 应该遵循 Keep a Changelog 规范。核心原则:

  • 每个版本单独一个区块
  • 按 Added、Changed、Deprecated、Removed、Fixed、Security 分类
  • 每条记录要具体,能让人看懂

举个例子:

## [2.1.0] - 2024-03-15

### Added
- 新增 `UserManager.getProfile()` 接口,支持获取用户详细信息
- 新增日志级别动态调整功能,可通过 `setLogLevel()` 在运行时切换

### Changed
- 优化网络请求的重试策略,默认重试次数从 3 次改为 2 次
- 升级底层加密库从 OpenSSL 1.1.1 到 3.0.0

### Fixed
- 修复在 Android 12 上调用 `startLocation()` 偶现崩溃的问题
- 修复 iOS 端内存泄漏,涉及 `ImageLoader` 类的循环引用

### Deprecated
- `getUserInfo()` 方法已标记为废弃,请使用 `getProfile()` 替代

看到了吗?每条记录都告诉用户「改了啥、为什么改、怎么用新的」。这才是合格的 Changelog。

注意:千万别在 Changelog 里写「内部重构」「代码优化」这种话。用户不关心你重构了什么,他们只关心「这个版本对我有什么影响」。

向后兼容性保证:SDK 的生命线

向后兼容性,说白了就是「老用户的代码能不能继续跑」。这是 SDK 开发中最容易翻车的地方。

我曾经在一个支付 SDK 里,把一个方法的参数从 int 改成了 long。当时觉得「反正 Java 会自动转型,没问题」。结果用户那边用的是 C++ 绑定,类型不匹配直接编译不过。那次事故让我记住了:永远不要假设用户的调用方式和你一样。

保证向后兼容性,我总结了几个实战经验:

  • 接口签名不要改:方法名、参数类型、返回值类型,动了就是破坏兼容性。真要改,加新方法,废弃旧方法。
  • 新增字段要给默认值:比如 JSON 返回里加了个新字段,老客户端解析不到怎么办?给个合理的默认值。
  • 废弃接口要留过渡期:标记 @Deprecated 后,至少保留两个大版本再删除。给用户迁移的时间。
  • 行为变更要谨慎:有时候接口没变,但内部行为变了。比如之前返回 null,现在返回空列表。这种「隐形破坏」最坑人。

我的原则:每次发布前,跑一遍老版本的单元测试。如果老测试用例在新版本上失败了,那就是破坏兼容性了。别犹豫,改回去。

知识体系总览

下面这张图,把 SDK 版本管理的核心逻辑串起来了。你可以把它当作一个检查清单:

SDK 版本管理知识体系 版本管理 语义化版本规范 主版本号:不兼容修改 次版本号:新增功能 修订号:问题修复 版本号生成策略 手动管理:VERSION 文件 自动生成:Git Tag / CI 预发布:-alpha / -beta Changelog 规范 按版本区块组织 分类:Added/Changed/Fixed 每条记录要具体可读 向后兼容性保证 接口签名不改 新增字段给默认值 废弃接口留过渡期 跑老版本单元测试 目标:让用户明确知道「这个版本对我意味着什么」

实战中的几个坑

最后分享几个我踩过的坑,希望能帮你少走弯路。

坑一:版本号跳得太快。 有个项目从 1.0.0 直接跳到 2.0.0,就改了个日志格式。用户一看主版本号变了,以为 API 全改了,吓得不敢升级。其实完全没必要。

坑二:Changelog 只写内部编号。 比如「修复了 JIRA-1234」。用户哪知道 JIRA-1234 是啥?他们只想知道「这个 bug 会不会影响我」。

坑三:偷偷改行为。 我曾经在一个次版本更新里,把某个接口的默认超时时间从 30 秒改成了 10 秒。结果用户那边业务逻辑依赖这个超时时间,直接崩了。嗯,从那以后我改任何默认值都会在 Changelog 里大写加粗提醒。

我的建议:每次发布前,花 10 分钟写一份「升级指南」。告诉用户这个版本改了啥、怎么迁移、有什么注意事项。这份文档比 Changelog 更详细,适合大版本升级时用。

版本管理看起来是小事,但做不好真的会劝退用户。你想想看,一个 SDK 连版本号都管不明白,用户怎么敢把它用到生产环境?

好了,这一章的内容就到这里。记住一句话:版本号是 SDK 的名片,Changelog 是 SDK 的说明书,向后兼容是 SDK 的信用。这三样做好了,你的 SDK 就成功了一半。

可可精品资料库