Skip to content

发布与回滚操作手册

爱生活 App(uni-app)热更新发布/回滚的完整操作流程,含踩坑记录。 相关代码:scripts/release-gitee.mjssrc/stores/update.store.tssrc/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 前置

  1. HBuilderX 里把版本号改成新版本(versionName + versionCode)
  2. HBuilderX → 发行 → 制作应用资源升级包(wgt),产物在 unpackage/release/__UNI__B962090.wgt
  3. 准备 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

脚本自动完成:

  1. wgt 包内 manifest 读取权威版本号(tag、version.json 的 versionCode 都以它为准)
  2. 在发布仓库创建/复用 Release(tag v1.0.x)并上传 wgt 附件
  3. 计算 sha256/size,回写本地 src/static/version.json
  4. 把 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.jsonversionCode 改回上一个好版本的 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