ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

OpenClaw Android 版本管理实战:CalVer 版本模型、共享移动发布流水线与 Play 签名机制全解

2026/9/11 6:04:58 拓冰建站 浏览量
OpenClaw Android 版本管理实战:CalVer 版本模型、共享移动发布流水线与 Play 签名机制全解 OpenClaw Android 版本管理实战CalVer 版本模型、共享移动发布流水线与 Play 签名机制全解【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 项目地址: https://gitcode.com/GitHub_Trending/cl/openclawOpenClaw Android 客户端手机 App 与 Wear OS 表盘应用采用**固定版本元数据 共享移动发布切割器mobile release cutter**的方式管理版本而非在build.gradle.kts中自动递增。本文以 apps/android/VERSIONING.md 为骨架结合仓库中的版本脚本、Gradle 构建配置与 Fastlane 发布链路源码完整讲解其 CalVer 版本模型、versionCode编码规则、Android/iOS 共享发布流程、Play 上传的 SHA 追踪以及签名资产的管理方式。读完本文你将能理解并操作从“写入 changelog”到“Play 商店原子上传”的完整 Android 发布链路并掌握pnpm android:*系列命令的职责边界。版本模型不自动递增只读固定元数据Android 发布构建release builds使用提交进仓库的固定 app 元数据作为唯一版本来源刻意避免在 Gradle 中做自动版本递增auto-bumping。整个版本体系由四个文件协同构成文件角色apps/mobile/version.json共享移动网关版本源gateway version source同时驱动 iOS 与 Androidapps/android/version.json提交进仓库的 Android 商店版本/版本号store version/code唯一来源apps/android/Config/Version.properties由version.json生成、被 Gradle 直接读取的属性文件apps/android/fastlane/metadata/android/en-US/release_notes.txtPlay 商店发布说明从共享 changelog 切割生成两个 changelog 分工明确apps/ios/CHANGELOG.md是共享移动发布说明的来源Android 的 Play 发布说明从它切割而来而 apps/android/CHANGELOG.md 仅保留历史 Android 发布文档共享移动切割器既不修改也不读取它。当前仓库中的真实取值示例apps/android/version.json内容{ version: 2026.8.2, versionCode: 2026080201 }对应生成的apps/android/Config/Version.properties# Shared Android version defaults. # Source of truth: apps/android/version.json OPENCLAW_ANDROID_VERSION_NAME2026.8.2 OPENCLAW_ANDROID_VERSION_CODE2026080201CalVer 语义版本与 versionCode 编码规则version即 Play 商店的versionName采用CalVer 日历版本格式YYYY.M.D例如2026.6.2、2026.8.2versionCode使用YYYYMMDDNN格式前 8 位是日期末尾两位NN是同一天内的构建序号手机Phone构建序号NN取值01 到 49配套的 Wear OS APK 通过给手机versionCode加 50保留 5199 区间——因为手机与 Wear 共享同一个 application IDai.openclaw.app见 apps/android/app/build.gradle.ktsPlay 要求同一应用 ID 下每个形态因子form factor的 versionCode 全局唯一。文档给出的示例组合版本手机 versionCodeWear versionCode2026.6.2202606020120260602512026.6.2同发布序列再次上传202606020220260602522026.6.10第 8 次上传20260610082026061058编码规则的源码级约束scripts/lib/android-version.ts 中实现了这些规则并做了硬性校验canonicalAndroidVersionCode(version)第 L51-L65 行将YYYY.M.D的月和补丁位补零后拼接01生成YYYYMMDD01形式的规范 versionCode并校验其不超过平台上限2_100_000_000normalizeAndroidVersionCode第 L67-L94 行强制 versionCode 必须以“规范前缀 两位后缀”的形式存在后缀必须落在0199区间否则直接报错wearVersionCode位于 scripts/mobile-release-version.ts取versionCode % 100得到构建号若不在 0149 之间则抛错随后50得到 Wear 版本号并再次校验不超过平台上限。也就是说手机端 49 次上传内不可用是刻意设计一旦某天 build 号达到 5050就会侵入 Wear 预留区间脚本会在准备阶段就拒绝生成。这与“Wear 预留 5199”的文档规则在代码层面完全对齐。Gradle 读取链路Version.properties 是构建时唯一入口虽然apps/android/version.json是版本事实来源但 Gradle 构建并不直接读 JSON而是读取生成好的Config/Version.properties。apps/android/app/build.gradle.kts 展示了这条链路val openClawAndroidVersionFile rootProject.file(Config/Version.properties) val openClawAndroidVersionProperties Properties().apply { if (!openClawAndroidVersionFile.isFile) { error(Missing Android version properties. $openClawMobileCutterInstruction) } openClawAndroidVersionFile.inputStream().use(::load) } fun requireOpenClawAndroidVersionProperty(name: String): String openClawAndroidVersionProperties.getProperty(name)?.trim()?.takeIf { it.isNotEmpty() } ?: error(Missing $name in Config/Version.properties. $openClawMobileCutterInstruction) val openClawAndroidVersionName requireOpenClawAndroidVersionProperty(OPENCLAW_ANDROID_VERSION_NAME) val openClawAndroidVersionCode requireOpenClawAndroidVersionProperty(OPENCLAW_ANDROID_VERSION_CODE).toIntOrNull() ?: error(OPENCLAW_ANDROID_VERSION_CODE must be an integer in Config/Version.properties.)关键设计点文件缺失或属性不合法时Gradle 会在配置阶段configuration phase直接失败错误信息还会附带“请先运行scripts/mobile-release-version.ts --prepare再--finalize”的指引把开发者导向正确的修复路径。Wear 模块 apps/android/wear/build.gradle.kts 采用完全相同的读取方式确保两个形态因子的版本同源。命令行工具查询、检查与退役入口查询与检查命令pnpm android:version pnpm android:version:check pnpm android:release:signing:plan MATCH_PASSWORDsigning repo password pnpm android:release:signing:sync:pull pnpm android:release:preflight各命令在 package.json 中的真实定义与职责如下命令底层实现职责pnpm android:versionscripts/android-version.ts --json只读查询输出解析后的 Android 版本 JSON含 canonicalVersion 与 versionCodepnpm android:version:checkscripts/android-sync-versioning.ts --check校验提交的 Android 属性与发布说明是否与来源一致绝不写任何发布元数据pnpm android:release:signing:planscripts/lib/android-fastlane.sh→signing_plan展示签名资产同步计划pnpm android:release:signing:sync:pull同上 →signing_sync_pull需要MATCH_PASSWORD从私有apps-signing仓库解密拉取签名资产pnpm android:release:preflight同上 →release_preflight发布前总校验Play 认证、签名、已提交的切割产物、发布说明scripts/android-version.ts还支持--shell输出模式直接导出可供脚本source的环境变量OPENCLAW_ANDROID_VERSION_NAMEversion OPENCLAW_ANDROID_VERSION_CODEversionCode已退役的入口pnpm android:version:sync与pnpm android:version:pin分别对应scripts/android-sync-versioning.ts --write与scripts/android-pin-version.ts是已退休的发布入口它们只会在失败时不写入任何文件所有版本、versionCode、属性或发布说明的变更都必须改由共享移动切割器完成。如果你在历史命令文档或 CI 配置中看到它们请不要再作为版本修改手段使用。共享移动发布切割器一次准备、两端发布Android 与 iOS 的版本由同一套“共享移动切割器”驱动核心脚本是 scripts/mobile-release-version.ts。它定义了一组固定的发布路径常量第 L20-L26 行export const MOBILE_RELEASE_PATHS [ apps/mobile/version.json, apps/android/version.json, apps/android/Config/Version.properties, apps/android/fastlane/metadata/android/en-US/release_notes.txt, apps/ios/CHANGELOG.md, ] as const;脚本支持--prepare与--finalize两个阶段node --import tsx scripts/mobile-release-version.ts --prepare --version YYYY.M.PATCH [--check|--write] [--root dir] node --import tsx scripts/mobile-release-version.ts --finalize --version YYYY.M.PATCH --plan ios-plan.json [--check|--write] [--root dir]prepare 阶段生成 Android 侧全部元数据--prepare阶段第 L268-L277 行会做四件事从apps/ios/CHANGELOG.md的## Unreleased章节切割 Android 发布说明renderAndroidReleaseNotes校验发布说明不超过500 个 Unicode 字符Google Play 硬限制scripts/lib/android-version.ts 中逐字符计数含生成的新行校验版本不得回退——移动网关版本与 Android 版本都只能前进生成对apps/mobile/version.json、apps/android/version.json、Config/Version.properties、release_notes.txt四处文件的新内容。版本号与 versionCode 的联动规则在expectedPreparedChanges第 L224-L227 行中若目标版本与当前 Android 版本相同则保留现有 versionCode允许同日多上传若不同则用canonicalAndroidVersionCode生成全新的YYYYMMDD01。finalize 阶段以 iOS 计划为准收尾--finalize必须携带 iOS release plan JSON--plan ios-plan.json。脚本会校验计划中的gatewayVersion与移动网关版本一致、App Store 版本编码正确validateIosPlan第 L157-L182 行切割 iOS changelog 的Unreleased章节为正式版本章节重新从正式章节生成 Android 发布说明检查此前 prepare 的产物是否仍与预期一致发现过期状态直接报错第 L299-L307 行将 iOS changelog 的切割结果一并写入。所有文件写入都采用先写临时文件再原子 rename的方式applyMobileReleasePlan第 L323-L343 行避免半写入状态若--check模式发现差异则仅输出待更新路径列表并以退出码 1 结束不会触碰任何文件。完整发布工作流Release Workflow文档给出的 11 步完整流程每一步都有明确的命令与责任人写共享说明在apps/ios/CHANGELOG.md的## Unreleased下补充共享移动发布说明准备版本执行node --import tsx scripts/mobile-release-version.ts --prepare --version 2026.8.2 --writeiOS 规划运行 live iOS planner并用其 JSON 计划 finalize 共享发布校验 Android 状态pnpm android:version:check确认提交的 Android 属性与发布说明一致该命令永不写元数据拉取签名资产MATCH_PASSWORDsigning repo password pnpm android:release:signing:sync:pull从apps-signing解密 Android 签名材料发布前预检pnpm android:release:preflight校验 Play 认证、签名、切割产物与发布说明刷新商店截图pnpm android:screenshots用脚本管理的 Pixel 2手机与 Wear OS Large Round 模拟器重拍 Play 截图产出归档pnpm android:release:archive生成签名手机 Play AAB、Wear AAB 以及第三方分发 APK原子上传pnpm android:release:upload在**一次 Google Play 原子编辑atomic edit**中上传元数据、截图、手机 AAB 与 Wear AAB 到各自的default与wear:轨道正式发布分发常规 final 或 correction 发布由OpenClaw Release Publish在核心 npm 发布成功后触发受保护的Android Release工作流对应 .github/workflows/android-release.yml从精确 tag 构建签名第三方 APK并附带校验清单checksum manifest与 GitHub provenancecorrection 发布前必须先递增固定的 versionCode工作流会校验其高于前一 final/correction APK同提交 fallback correction 则复用基础发布已验证的 APK 并仅追加 provenance商店收尾必要时在 Google Play Console 手动完成生产环境全量上线。失败即停的纪律pnpm android:release:upload一旦失败必须停在失败点禁止用android:release:archive、android:release:metadata、直接 Fastlane lane、Gradle release 产物、Google Play API 变更命令或 Play Console 变更命令绕过重传。正确做法是修复失败的 release-lane 步骤后重新运行pnpm android:release:upload。同理Agent 驱动的发布不得使用低层签名/上传接口绕过失败的 upload应当上报失败步骤并等待维护者指示。第三方分发的边界第三方third-partyflavor 会归档为签名 APK 用于非 Play 分发Play release lane 从不上传它。官方 GitHub 分发仅由.github/workflows/android-release.yml持有该工作流通过受保护的android-release环境以OpenClaw-Android.apk文件名发布 regular final 与 correction tag。发布 SHA 追踪不可变 ref 即上传证据每次成功的 Play 构建上传都会创建一个非 tag 的 Git ref记录上传商店构建对应的源码提交refs/openclaw/mobile-releases/android/versionName-versionCode真实示例refs/openclaw/mobile-releases/android/2026.6.10-2026061008这些 ref 刻意放在refs/tags/*与refs/heads/*之外因此不会出现在 GitHub release 或 tag 页面上也不参与 OpenClaw 核心发布机制。pnpm android:release:upload的写入时机语义上传前检查 ref仅在原子性的手机 Wear Play 编辑提交后才记录ref不可变同一 ref 相同 SHA 可重复接受同一 ref 不同 SHA 直接失败GOOGLE_PLAY_VALIDATE_ONLY1模式下仍会检查 ref但因未真正发布 Play 构建不会记录手动 fallback 上传后严禁手工创建该 ref——它是 release-lane 的证据不是失败upload的修复机制。配套的两个直接查询命令跳过整个发布流水线仅做平台侧解析/预检pnpm mobile:release:preflight -- --platform android --version 2026.6.10 --version-code 2026061008 pnpm mobile:release:resolve -- --platform android --version 2026.6.10 --version-code 2026061008此外android:version:check还能校验冻结的“前切割器”Android 基线与其精确历史 changelog 条目是否匹配而 Fastlane release lanes 额外要求 Android pin 与apps/mobile/version.json一致从而保证历史基线不可能被当作新移动版本上传。签名模型apps-signing 仓库 MATCH_PASSWORDapps/android/Config/ReleaseSigning.json 将 Android 签名资产**固定pin**在共享的私有apps-signing仓库中。Android 流水线与 iOS 共用同一个MATCH_PASSWORDrelease-owner 密钥但文件管理方式不同Android 由 scripts/android-release-signing.mjs 负责而非 iOS 的 Fastlanematch。sync:pull会把 Play 上传 keystore 与 Gradle 签名属性解密到apps/android/build/release-signing/目录——该目录被 gitignore 忽略Fastlane 再将解密后的值以Gradle project properties形式导出给当前 release 命令使用。无 MATCH_PASSWORD 时的手动签名路径当MATCH_PASSWORD未设置时原有的手动 Gradle 属性签名路径依然可用在本地 Gradle user properties~/.gradle/gradle.properties中提供以下四个属性后再运行 release 任务属性含义OPENCLAW_ANDROID_STORE_FILEkeystore 文件路径OPENCLAW_ANDROID_STORE_PASSWORDkeystore 密码OPENCLAW_ANDROID_KEY_ALIAS签名 key 别名OPENCLAW_ANDROID_KEY_PASSWORD签名 key 密码需要强调的是该手动路径仅面向正常开发场景Agent 驱动的发布不得用它绕过失败的pnpm android:release:upload遇到失败应上报并等待维护者处理。小结一条可验证、可回查的版本发布闭环OpenClaw Android 的版本管理可以概括为一条闭环共享 changelog 与网关版本 → 共享移动切割器统一生成 Android/iOS 元数据 → Gradle 从Config/Version.properties读取 → Fastlane 原子上传到 Play 并记录不可变 SHA ref。其核心设计意图清晰单一事实来源手机、Wear、iOS 的版本与说明全部由apps/mobile/version.jsonapps/ios/CHANGELOG.md派生杜绝各端漂移平台约束前置CalVer 编码、Wear 50 偏移、500 字符说明限制、版本不可回退等规则全部下沉到脚本与 Gradle 配置阶段校验失败发生在构建/发布之前而非 Play 审核之后可审计、可追溯不可变 SHA ref、受保护发布工作流、--check只读校验共同构成“上传即证据、证据不可篡改”的发布纪律。对于需要在 OpenClaw 仓库中处理 Android 版本或发布的人来说请始终牢记两条铁律一切版本变更走共享移动切割器prepare → iOS plan → finalizeupload失败后只修步骤、重跑命令绝不绕路。【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考