发布与回滚操作手册
爱生活 App(uni-app)热更新发布/回滚的完整操作流程,含踩坑记录。 相关代码:
scripts/release-gitee.mjs、src/stores/update.store.ts、src/components/common/UpdatePrompt.vue架构说明见docs/update-and-analytics.md。
0. 关键架构速览
wgt 发布 → Gitee Releases 附件(公开仓库 lutlelk/ai-life-os-release)
→ version.json(公开仓库根目录,raw 链接)
→ App 启动解锁 → 全局弹窗「发现新版本」
→ 下载(HTTPS + 大小校验)→ 安装
→ 2.5s 后自动重启(重启前关闭 SQLite 原生连接)
→ 新版本生效,检查更新显示"已是最新"- 源码仓库:
lutlelk/ai-life-os(私有,只读版本号,不写内容) - 发布仓库:
lutlelk/ai-life-os-release(必须公开,私有仓库附件匿名下载 403) - App 读取的清单地址:
https://gitee.com/lutlelk/ai-life-os-release/raw/master/version.json(代码内置默认值,无需配置)
1. 版本号规则
| 字段 | 规则 | 示例 |
|---|---|---|
versionName(manifest) | 用户可见版本号 | 1.0.10 |
versionCode(manifest) | 纯递增整数,只要求比上一个版本大 | 109 → 110(1.0.9 → 1.0.10) |
package.json version | 与 versionName 保持一致(发布时同步) | 1.0.10 |
重要:versionCode 只用于比大小(Android 要求整数递增),不需要能还原成版本号,不要用段位编码(101010 之类),每次 +1 即可。
版本修改入口:HBuilderX → manifest.json 可视化界面 → 基础配置 → 版本号。改完制作 wgt,发布脚本会从 wgt 包内自动读取,无需手动同步其他文件。
2. 发布流程(一条命令)
2.1 前置
- HBuilderX 里把版本号改成新版本(versionName + versionCode)
- HBuilderX → 发行 → 制作应用资源升级包(wgt),产物在
unpackage/release/__UNI__B962090.wgt - 准备 Gitee 私人令牌(头像 → 设置 → 安全设置 → 私人令牌,勾选 releases 权限)
2.2 一键发布
bash
GITEE_TOKEN=你的令牌 node scripts/release-gitee.mjs \
--release-repo lutlelk/ai-life-os-release \
--files unpackage/release/__UNI__B962090.wgt \
--changelog "🎉 爱生活 1.0.x
- 更新内容1
- 更新内容2" \
--update-manifest src/static/version.json \
--push-manifest脚本自动完成:
- 从 wgt 包内 manifest 读取权威版本号(tag、version.json 的 versionCode 都以它为准)
- 在发布仓库创建/复用 Release(tag
v1.0.x)并上传 wgt 附件 - 计算 sha256/size,回写本地
src/static/version.json - 把 version.json 推送到发布仓库根目录(App 端 raw 链接读取)
⚠️ 同步
package.json的 version 与本次发布一致(发布脚本用 wgt 内版本,package.json 仅仓库管理用,建议同步避免混淆)。
2.3 发布后验收(必做)
bash
# ① 版本清单(匿名读取,等 ~1 分钟 CDN 传播)
curl -sL "https://gitee.com/lutlelk/ai-life-os-release/raw/master/version.json"
# 应显示:versionName / versionCode(与本次发布一致)/ wgt.size
# ② wgt 匿名下载
curl -sL -o /tmp/dl.wgt -w "HTTP=%{http_code} 大小=%{size_download}\n" \
"https://gitee.com/lutlelk/ai-life-os-release/releases/download/v1.0.x/__UNI__B962090.wgt"
# 应返回 200,大小与本地一致
# ③ 哈希一致性(下载内容与本地包必须一致)
shasum -a 256 /tmp/dl.wgt unpackage/release/__UNI__B962090.wgt
# ④ 真机验证:更新到新版本后,
# 关于应用 = 检查更新页 = 新版本号(同取 plus.runtime 运行时版本)3. 回滚方案
3.1 未更新用户(止血)
把 src/static/version.json 的 versionCode 改回上一个好版本的 code,重新推送到发布仓库:
bash
# 修改 version.json 后推送(脚本的 push 逻辑)
GITEE_TOKEN=你的令牌 node -e "
const { readFileSync } = require('fs');
(async () => {
const content = readFileSync('src/static/version.json').toString('base64');
const T = process.env.GITEE_TOKEN;
const api = async (p, m, b) => {
const r = await fetch('https://gitee.com/api/v5' + p + '?access_token=' + T, {
method: m, headers: b ? {'Content-Type':'application/json'} : undefined,
body: b ? JSON.stringify(b) : undefined,
});
const t = await r.text();
if (!r.ok) throw new Error(m + ' ' + p + ' ' + r.status + ': ' + t.slice(0,200));
return JSON.parse(t);
};
const ex = await api('/repos/lutlelk/ai-life-os-release/contents/version.json');
await api('/repos/lutlelk/ai-life-os-release/contents/version.json', 'PUT', {
content, sha: ex.sha, message: 'rollback: 恢复旧版本',
});
})();
"效果:未更新用户检查时 旧code >= 自己code → 显示"已是最新",不再被坏版本骚扰。
3.2 已更新用户
wgt 不能自动降级(版本只能升,低版本 wgt 需 force 才装得上)。已更新到坏版的用户:
- 方案 A:发一个修复版 wgt(bump 新版本号),走正常更新流程
- 方案 B:重新侧载安装基础 APK(
npm run build:app-android或 HBuilderX 云打包)
旧 Release 的 wgt 附件永久保留(每个 tag 一份),回滚时可把 version.json 的
platforms.wgt.url指回旧附件,但只能阻止未更新的用户,无法降级已更新的。
4. 常见问题(实战踩坑)
| 问题 | 原因 | 处理 |
|---|---|---|
| 发布后 version.json 的 versionCode 不对 | HBuilderX 会反复把 src/manifest.json 回退成旧版本 | 发布脚本已改为从 wgt 包内读版本,不受影响;改版本号务必在 HBuilderX 界面改 |
| 远端 version.json 延迟 ~1 分钟 | Gitee raw CDN 缓存 | 发布后等 1 分钟再验收 |
| 私有仓库附件下载 403 | 私有仓库附件需登录 | 发布仓库必须设为公开 |
| H5 无法直接读取 Gitee 文件 | Gitee raw/附件不带 CORS 头 | H5 端 version.json 走同源 /static/version.json(跟随 H5 部署) |
| 热更新重启后仪表盘空数据 | plus.runtime.restart() 软重启不释放原生 SQLite 连接 | 已修复:重启前 closeNativeDatabase()(src/database/index.ts) |
| 重启后锁屏不弹 / router-view 警告 | 立即重启(wgt 未落盘)导致运行时损坏 | 已修复:安装成功后延迟 2.5s 再重启 |
Gitee API 建 Release 报 target_commitish is missing | 文档说可省,实测必填 | 脚本已自动取仓库默认分支 |
5. 令牌安全
- 私人令牌只在生成时显示一次,务必立即保存
- 不要写进仓库/代码;用环境变量
GITEE_TOKEN传入 - 只要令牌在对话/日志中出现过,用完立即轮换(生成新令牌,旧的作废)
6. 日常迭代流程(简版)
① 改代码 → 本地验证(npm run type-check / npm test)
② HBuilderX 改版本号 → 制作 wgt
③ 一键发布(§2.2)→ 验收(§2.3)
④ 攒改动,测试通过后一次性 git commit + push
⑤ 问题回滚按 §3