fd50a7fdf336b46ee7e07cd94ca3cda0c0c4123a
opendance-android
OpenDance Studio 阶段三:Android 辅助 App(Kotlin + CameraX + MediaPipe 端侧推理)。
用手机摄像头做端侧姿态推理,把 33 个骨骼关键点通过 WebSocket 推给 Windows 客户端, 由后者驱动 VRM 角色并 DTW 实时评分。
画面不离开设备。通过网络发送的只有 33 个关键点坐标,不含任何图像数据。
状态
阶段三已完成:T-AND-001 → T-AND-009 全部落地。
| 验收项 | 结果 |
|---|---|
| 单元测试 | ✓ 25 项全部通过(JVM,无需设备) |
| 跨端金标准 | ✓ Kotlin 序列化器与 Web 端 TypeScript 实现逐位一致 |
./gradlew assembleRelease |
✓ 生成已签名 APK(28.6 MB) |
| 签名校验 | ✓ apksigner 退出码 0,v2 方案,CN=OpenDance Studio Dev |
| 包信息 | ✓ com.opendance.studio v0.1.0,minSdk 29(Android 10+)/ targetSdk 34 |
| 模型随包分发 | ✓ assets/pose_landmarker_lite.task 5.7 MB(Stored 未压缩) |
| ABI 覆盖 | ✓ arm64-v8a + armeabi-v7a(debug 额外含 x86/x86_64) |
快速开始
export JAVA_HOME=/path/to/jdk17 # AGP 8.7.3 要求
export ANDROID_HOME=/path/to/android-sdk
bash build/gen-keystore.sh # 生成发布签名(首次;不入库,请自行备份)
bash build/verify.sh # 单元测试 → 构建 → 产物校验
bash build/build-apk.sh all # 仅构建 debug + release
bash build/package-release.sh # 打发布包
详细使用说明见 README.txt,工程约束见 DSH.md。
技术栈
| 组件 | 选型 |
|---|---|
| 语言 | Kotlin 2.0.21 |
| 构建 | AGP 8.7.3 + Gradle 8.9 + JDK 17 |
| 相机 | CameraX 1.4.0 |
| 推理 | MediaPipe Tasks Vision 0.10.35 |
| 通信 | OkHttp 4.12.0 |
| UI | Jetpack Compose(BOM 2024.10.01,Material3) |
数据流
CameraX(ImageAnalysis) ──▶ MediaPipe PoseLandmarker(端侧推理)
│ 33 点归一化坐标
┌─────────────────────┴─────────────────────┐
▼ ▼
KeypointFrame(239B) ──▶ WebSocket ──▶ Windows 骨架叠加层
app/src/main/java/com/opendance/studio/
├── model/ 239 字节帧编解码 + 33 点拓扑(契约核心)
├── camera/ CameraX 采集
├── pose/ MediaPipe 端侧推理
├── net/ WebSocket 推流 + 局域网主机发现
├── data/ 设置持久化
└── ui/ 连接页 / 运行页 / 关于页
依赖的契约(opendance-web v0.1.0 冻结)
contracts/websocket-keypoints.md— 239 字节关键点帧(本端为发送方)contracts/skeleton-topology.md— MediaPipe 33 点索引与坐标语义contracts/open-source-credits.md— 关于页必须展示的开源声明
contracts/ 是只读快照。任何跨端契约变更必须先回到
opendance-web 修改并提升版本。
跨端一致性:金标准字节向量测试
本仓库最重要的测试不是「函数跑通了」,而是与另两端逐位一致:
KeypointFrameTest.goldenVectorMatchesWebImplementation 用 opendance-web 已通过验收的
TypeScript 实现生成 239 字节金标准向量,断言 Kotlin 实现产出完全相同的字节。
这条测试同时守护三端(TypeScript / GDScript / Kotlin),任何一端私自改字段布局都会立刻失败。
已知限制
- Godot(Windows 端)的
WebSocketPeer不暴露握手请求路径,因此无法校验 path 是否为/pose, 本端仍按契约连接到/pose,互操作不受影响。 - 未在真实 Android 设备上安装运行(本环境无设备也无模拟器)。 已验证到:构建通过、签名有效、包信息正确、模型与 4 个 ABI 的 native 库均正确打包。
- 主机发现依赖手机与电脑处于同一 WiFi;路由器开启 AP 隔离时无法互访(见 README.txt FAQ)。
- release 包只含 arm64-v8a + armeabi-v7a。x86/x86_64 仅供模拟器,会占掉约 27 MB, 对真机用户没有价值;debug 包保留全部 4 个 ABI 以便模拟器调试。
第三方开源声明
见 THIRD_PARTY.md,或应用内「关于」页面。
未使用 SMPL 模型及其衍生拓扑,统一采用 MediaPipe 33 点拓扑。