Files
opendance-android/tasks/014-release-acceptance.md
T
zijunchiang c207e7dadd test(accept): 发布包级端到端验收(读 zip 内 APK)+ T-AND-014
`build/verify.sh` 验的是 app/build/outputs/ 里**刚构建**的 APK,而用户装的是 zip
里的 app-release.apk。两端都因此翻过车(Web v0.7.4 实体注册、Windows v0.2.1 的
PE 版本元数据),故三端统一:每次发布都要有一条读产物本身的验收(文档 §7.5)。

新增 build/accept-release.sh,对一个 zip(或已解压目录)跑完:
  1) sha256(有 SHA256SUMS 时);
  2) 解压 + 文件清单(apk / README.txt / THIRD_PARTY.md / contracts/VERSION);
  3) APK 的 AndroidManifest versionName/versionCode = 发布版本(复用
     check-apk-version.sh —— 安装界面与应用信息页读的就是它);
  4) ABI 恰为 arm64-v8a + armeabi-v7a、无模拟器 ABI,且两个 ABI 下都有
     MediaPipe native 库(T-AND-012 崩溃根因之一);
  5) assets/pose_landmarker_lite.task 在包内;dex 里仍有
     poselandmarker/PoseLandmarker(R8 没整体裁掉);
  6) 有 apksigner 时顺带验签;
  7) 包内 contracts/VERSION 与仓库逐项一致(抓「APK 用旧契约构建、快照拷了新的」)。
package-release.sh 结尾打印下一步验收命令;README 补用法。

实测(对**已发布**的 v0.2.0 资产重新下载后跑):sha256 OK、版本元数据 0.2.0/200、
ABI 恰为两个真机 ABI、两个 ABI 下都有 MediaPipe native、模型资源在、dex 命中
PoseLandmarker、apksigner 通过、契约快照与仓库一致 → 发布包级验收全部通过。

反向验证(真实负例):
  * 篡改包内 contracts/VERSION 的 data-models=0.6.0 →
    ✗ data-models:包内 0.6.0,仓库 0.7.0,退出码 1;
  * 期望版本写 0.2.1 对 v0.2.0 的包 → ✗ versionName 是 '0.2.0',期望 '0.2.1'
    且 ✗ versionCode 是 200,期望 201。

诚实声明:**装到真机跑 30 分钟**这条脚本替代不了,仍属设备实测项;本脚本能证明的是
「装得上、不会因打包配置而崩」。verify.sh 仍全绿。
2026-09-17 04:51:16 +08:00

3.1 KiB
Raw Blame History

T-AND-014:发布包级端到端验收(读 zip 内的 APK)

  • 状态: done
  • 依赖: T-AND-013(APK 版本元数据)/ T-AND-009(打包)
  • 文档: v1.6 §6.3 / §7.5 / §11
  • 契约: 不涉及(验收流程)

为什么需要

build/verify.sh 验的是 app/build/outputs/ 里刚构建的 APK,而用户装的是 zip 里的 app-release.apk。两者之间隔着打包与分发;本项目另两端都因此翻过车 (Web v0.7.4 的实体注册、Windows v0.2.1 的 PE 版本元数据),所以三端统一要求: 每次发布都要有一条读产物本身的验收(文档 §7.5)。

实现:build/accept-release.sh

对一个 zip(或已解压目录)跑完:

步骤 检查
1 sha256 校验(有 SHA256SUMS 时)
2 解压 + 文件清单(app-release.apk / README.txt / THIRD_PARTY.md / contracts/VERSION)
3 APK 的 AndroidManifest versionName/versionCode = 发布版本(复用 build/check-apk-version.sh;安装界面与应用信息页读的就是它)
4 ABI 恰为 arm64-v8a + armeabi-v7a(无模拟器 ABI),且两个 ABI 下都有 MediaPipe native 库(T-AND-012 崩溃根因之一)
5 assets/pose_landmarker_lite.task 随包分发;dex 里仍有 poselandmarker/PoseLandmarker(R8 没整体裁掉)
6 有 apksigner 时顺带验签(可选,不影响结论)
7 包内 contracts/VERSION 与仓库 contracts/VERSION 逐项一致(抓「APK 用旧契约构建、快照拷了新的」)

实测(对已发布的 v0.2.0 资产,重新下载后跑)

[accept] sha256 校验:opendance-android-v0.2.0.zip: OK
  ✓ app-release.apk / README.txt / THIRD_PARTY.md / contracts/VERSION
  ✓ APK 版本元数据一致:0.2.0(versionCode 200)
  ✓ ABI 恰为 arm64-v8a + armeabi-v7a(真机 ABI)
  ✓ lib/arm64-v8a 下有 MediaPipe native 库
  ✓ lib/armeabi-v7a 下有 MediaPipe native 库
  ✓ MediaPipe 模型资源随包分发(assets/pose_landmarker_lite.task)
  ✓ dex 中存在 poselandmarker/PoseLandmarker(R8 未整体裁掉 MediaPipe;命中 1 个 dex)
  ✓ apksigner 验签通过(退出码 0)
  ✓ 包内契约快照与仓库 contracts/VERSION 一致
 发布包级验收全部通过

反向验证

负例 结果
把包内 contracts/VERSION 的 data-models 改成 0.6.0 ✗ data-models:包内 0.6.0,仓库 0.7.0,退出码 1
期望版本写 0.2.1 对 v0.2.0 的包 ✗ versionName 是 '0.2.0',期望 '0.2.1' + versionCode 是 200,期望 201

仍未覆盖(诚实声明)

装到真机跑 30 分钟这条只能真机做,脚本无法替代。本脚本能证明的是: 包能验签安装(ABI 与 native 库齐备、模型资源在、R8 没裁掉类、版本元数据正确), 即「安装后不会因打包配置而崩」;运行时稳定性仍需设备实测。

用法

bash build/accept-release.sh dist-release/opendance-android-v0.2.0.zip
# 或对已解压目录:bash build/accept-release.sh dist-release/opendance-android-v0.2.0