Files
opendance-android/build/package-release.sh
T
zijunchiang 0ee95c46e0 test(release): 逐文件核对「发布包 == 打标签的树」(T-AND-018)
新增 build/check_tracked_release.py(纯标准库):对包内每个文件按路径决定比较基准 ——
app-release.apk 比工作树构建结果,其余比 git show <tag>:<路径>;内容不一致 / 多余 /
构建产物缺失都会列出并退出 1。已接入 accept-release.sh(第 0 步)与 package-release.sh 提示。

实测(已发布的 v0.2.2 资产重新下载后):
  包内 12 个文件:源码/文档 11(与 tag v0.2.2 比)+ 构建产物 1(APK 比工作树构建)
  ✓ 逐文件一致:0 处不一致 / 0 处多余 / 0 处缺失
同行产品级验收(版本元数据 0.2.2/202、native 体检、契约快照、验签)同时全绿。

踩坑:第一版把 BUILD_OUTPUTS 的键一律当目录前缀,而 APK 是单文件,拼出
app-release.apk/ 导致「工作树缺失」误报;现区分目录前缀与精确文件名。
2026-09-18 03:10:35 +08:00

105 lines
4.4 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ============================================================
# OpenDance Studio —— Android 辅助 App 发布打包
#
# 产物(文档 §6.3 / §11.2):
# opendance-android-vX.Y.Z.zip ← 单个完整包
# SHA256SUMS ← 裸文件名,下载目录内 sha256sum -c 直接可用
#
# 包内结构:
# opendance-android-vX.Y.Z/
# app-release.apk
# THIRD_PARTY.md
# README.txt README.md
# contracts/
#
# 版本号唯一来源是 app/build.gradle.kts 的 versionName;不传参数时自动读取,
# 并与 project.yaml 交叉校验(文档 §11.2:产物名 / tag / README / 界面必须一致)。
#
# 用法:bash build/package-release.sh [版本号]
# ============================================================
set -euo pipefail
PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
cd "$PROJECT_DIR"
# 先定义 log/die:下面的版本号校验就会用到 die,函数必须先于调用定义,
# 否则命中的是 "die: 未找到命令"(退出码 127,看不出真实原因)。
log() { printf '\033[1;34m[package]\033[0m %s\n' "$*"; }
die() { printf '\033[1;31m[error]\033[0m %s\n' "$*" >&2; exit 1; }
YAML_VERSION="$(sed -n 's/^version:[[:space:]]*//p' project.yaml | head -1)"
GRADLE_VERSION="$(sed -n 's/^[[:space:]]*versionName = "\(.*\)"/\1/p' app/build.gradle.kts | head -1)"
VERSION="${1:-$GRADLE_VERSION}"
VERSION="${VERSION:-0.2.0}"
[ -n "$YAML_VERSION" ] && [ "$VERSION" != "$YAML_VERSION" ] \
&& die "版本号不一致:参数/versionName=$VERSION,project.yaml=$YAML_VERSION"
[ -n "$GRADLE_VERSION" ] && [ "$VERSION" != "$GRADLE_VERSION" ] \
&& die "版本号不一致:参数=$VERSION,app/build.gradle.kts 的 versionName=$GRADLE_VERSION"
NAME="opendance-android-v${VERSION}"
OUT_DIR="$PROJECT_DIR/dist-release"
STAGE="$OUT_DIR/$NAME"
APK="app/build/outputs/apk/release/app-release.apk"
[ -f "$APK" ] || die "未找到 $APK,请先执行 bash build/build-apk.sh release"
# 源 APK 的 AndroidManifest 版本号必须是本次发布版本(文档 §11.2):
# 安装界面 / 应用信息页读的就是它,与 build.gradle.kts 的配置无关。
bash "$PROJECT_DIR/build/check-apk-version.sh" "$APK" "$VERSION" \
|| die "APK 的 versionName/versionCode 不是 v$VERSION;请用 bash build/build-apk.sh release 重新构建"
log "源 APK 版本元数据校验通过(=$VERSION)"
# APK 是 zip,校验魔数
MAGIC=$(head -c 2 "$APK" | od -An -tx1 | tr -d ' \n')
[ "$MAGIC" = "504b" ] || die "$APK 不是合法 APK(魔数 $MAGIC)"
log "整理产物到 $STAGE …"
rm -rf "$STAGE"
mkdir -p "$STAGE"
cp "$APK" "$STAGE/app-release.apk"
cp THIRD_PARTY.md README.txt "$STAGE/"
if [ -f README.md ]; then cp README.md "$STAGE/"; fi
cp -r contracts "$STAGE/contracts"
# ---- 完整性自检:APK 必须是合法 zip、含 MediaPipe 模型、ABI 只含真机 ABI ----
[ "$(head -c 2 "$APK" | od -An -tx1 | tr -d ' \n')" = "504b" ] || die "$APK 不是合法 APK"
unzip -l "$APK" | grep -q "assets/pose_landmarker_lite.task" || die "APK 缺少 MediaPipe 模型资源"
ABIS=$(unzip -l "$APK" | grep -oE "lib/[^/]+/" | sed 's#lib/##;s#/##' | sort -u | tr '\n' ' ')
log "APK 内 ABI:$ABIS"
for abi in arm64-v8a armeabi-v7a; do
echo "$ABIS" | grep -q "$abi" || die "APK 缺少 $abi 的 native 库"
done
if echo "$ABIS" | grep -qE "x86"; then
die "release APK 含模拟器 ABI($ABIS);请检查 abiFilters(T-AND-012)"
fi
unzip -l "$APK" | grep -q "lib/arm64-v8a/.*mediapipe" || die "arm64-v8a 下缺少 MediaPipe native 库"
ZIP="$OUT_DIR/$NAME.zip"
rm -f "$ZIP" "$OUT_DIR/SHA256SUMS"*
log "生成压缩包…"
( cd "$OUT_DIR" && zip -qr "$NAME.zip" "$NAME" )
# ---- SHA256SUMS(裸文件名,下载目录内可直接校验) ----
( cd "$OUT_DIR" && sha256sum "$NAME.zip" > SHA256SUMS )
log "完成:$ZIP($(du -h "$ZIP" | cut -f1))"
echo ""
echo "产物:"
echo " $ZIP"
echo " $OUT_DIR/SHA256SUMS"
if ( cd "$OUT_DIR" && sha256sum -c SHA256SUMS --status ); then
echo " sha256 校验:OK"
else
die "sha256 自校验失败"
fi
echo ""
unzip -l "$ZIP" | sed -n '4,20p'
echo ""
echo "分发:上传 $NAME.zip 与 SHA256SUMS 两个资产;用户下载后"
echo " sha256sum -c SHA256SUMS && unzip $NAME.zip"
echo " 再 adb install -r $NAME/app-release.apk(Android 10+)"
echo ""
echo "下一步(文档 §7.5 / §7.7:发布前必须做的验收,含逐文件核对):"
echo " python3 build/check_tracked_release.py $ZIP --tag v$VERSION"
echo " bash build/accept-release.sh $ZIP"