-
released this
2026-09-17 01:11:55 +08:00 | 7 commits to main since this release⚠️ 本版已被 v0.2.1 取代(建议直接用 v0.2.1):
v0.2.1 修掉了重连链路的一处真实缺陷 —— 上一次会话的关闭码会污染下一次会话,
导致重新开始推流后遇到网络失败时不再自动重连(只能反复手点)。
另新增 JVM 内以真实 WebSocket 验证重连链路的集成测试(8 项,无需设备)。OpenDance Studio -- Android 辅助 App v0.2.0
重连状态机修复(《DSH 开发文档 v1.6》6.5 / T-AND-011)、
MediaPipe 初始化崩溃修复(6.6 / T-AND-012)、
「关于」清单版本号(11 / T-AND-010)。契约
websocket-keypoints提升到 0.2.0(向后兼容:子协议名与二进制帧
version均不变,只新增可选控制字段与一种新控制类型),三端快照逐字节一致。一、连接状态异常 / 频繁重连(T-AND-011)
逐条核对后找到 3 个真实根因,都不是"退避参数没调好"这种表象问题:
根因 1:保活用错了层(最要命)
Windows 端有 5 秒静默超时,只看应用层收到的数据帧/文本帧;
而本端原先只有 OkHttp 的协议层 ping —— 它由底层库自动应答,
根本不会暴露给接收端的应用层,也就是说它不能续命。
结果:画面里没有人时 5 秒必然被踢、然后重连,循环往复。- 契约新增 1.1:接收端必须在
welcome/config中声明silentTimeoutMs与
heartbeatIntervalMs,且 心跳必须小于静默超时的一半; - 契约新增 3.6:应用层
ping/pong; - Windows 端超时 5s → 15s、期望心跳 5s,并在
welcome/config中下发; - 本端按声明值周期发
ping,连续 3 个周期没收到pong才判定链路已死并主动重连。
根因 2:不该重连的时候也重连
- 契约新增 7 关闭码策略:
1000/1001/1002与主动停止一律不重连,
避免"重连风暴"; - 退避与抖动按 7.1 冻结:0.5s → 1 → 2 → 4 → 8 → 15s 封顶 + ±20% 抖动。
根因 3:frame_id 恒为 0
PoseDetector.detect()算出safeTimestamp后忘了写回lastTimestampMs,
于是frameId永远是 0 —— 接收端据此做的丢包检测完全失效。已修。其他对齐
- 契约新增 8 连接状态机:
idle → resolving → connecting → handshaking → streaming → degraded → reconnecting → stopped,两端同名,可直接对照日志; - 契约新增 5 设备去重:
hello携带稳定deviceId(ANDROID_ID的 SHA-256
前 16 位,不含任何硬件序列号),Windows 端据此去重,"已连接 N 台"不再抖动; - 运行页显示状态机名、协商子协议、最近断开原因(close code + 中文说明)、
保活参数、心跳 RTT,并提供 「导出连接日志」(最近 500 条:状态迁移 /
close code / 子协议协商 / 首帧时间)。
二、MediaPipe 初始化崩溃(T-AND-012)
ExceptionInInitializerError: null的 message 为null,没有任何信息量 ——
真因一定在 cause 链里(通常是UnsatisfiedLinkError)。逐条核对 6.6 的五步,
本项目实际命中 三处:项 处理 拿到真因 新增 PoseDiagnostics:展开完整 cause 链取最内层真因,给出"缺少的具体库"ABI 核对 比较 Build.SUPPORTED_ABIS与 APK 内lib/<abi>/实际目录,直接指出"APK 只包含 arm64-v8a/armeabi-v7a,而模拟器(x86_64)需要 x86_64"这类必崩组合;构建期新增verifyReleaseAbi强制核对native 解压方式 packaging { jniLibs { useLegacyPackaging = true } }(AGP 8 的 release 默认extractNativeLibs=false,MediaPipe 的 JNI 加载对它有历史兼容问题)R8 细化 补 -keepclasseswithmembernames class com.google.mediapipe.** { native <methods>; },并用-printseeds输出 seeds 供发布前核对(实测保留 20169 条 MediaPipe 条目)未换库:诊断指向的是集成配置(native 解压 + R8 + ABI),不是 MediaPipe
本身不稳定,因此保留 MediaPipe(33 点契约零成本)。三、「关于」清单展示版本号(T-AND-010)
- 版本唯一来源
versionName(=project.yaml的version= APK 文件名 = Git tag);
versionCode按10000*主 + 100*次 + 修订递增(0.2.0→200); - 契约版本改为构建期解析
contracts/VERSION后注入BuildConfig
(六项契约各自独立递增,原先的单个CONTRACT_VERSION常量已失真),
关于页逐项列出;Kotlin 界面代码里不出现任何版本号字面量; - 新增
checkReleaseConsistency并挂到每个变体的preBuild:
versionName/project.yaml/contracts/VERSION/versionCode任一不自洽
直接 BUILD FAILED,不让版本漂移进入产物。
校验
- 单元测试 56 项全部通过(新增
ReconnectPolicyTest11 项、
PoseDiagnosticsTest12 项;金标准 239 字节向量测试仍逐位一致); bash build/verify.sh三步全通过:单元测试 → debug/release 构建 →
签名 / 包信息 / ABI / MediaPipe native 库 / R8 seeds / dex 关键类校验
(release ABI 恰为arm64-v8a+armeabi-v7a);opendance-android-v0.2.0.zipsha256:12db050f151a9ad6970646c5e1956918908c5662fd0dd38a8c3e12fc4d57423f
真机 30 分钟连续推流与「连续 30 分钟推理无崩溃」两项验收需要真机实测
(本环境无 Android 设备),根因修复与回归防护已由单测与构建期校验覆盖。安装
sha256sum -c SHA256SUMS unzip opendance-android-v0.2.0.zip adb install -r opendance-android-v0.2.0/app-release.apk也可直接把
app-release.apk拷到手机安装(Android 10+)。
安装后请到「关于」页确认显示v0.2.0与六项契约版本。Downloads
- 契约新增 1.1:接收端必须在