Files
freeboss b7b5518834 feat: dev-5.1 分支基线(v1.3.35 发版后代码 + 5.1 声道改造文档)
- 以 main(ccc65af) 为基线提交当前工作区代码
- 新增 5.1 声道改造文档两份
- .gitignore 补充 .vscode/、.screenshots/
2026-11-02 19:25:12 +08:00

167 lines
6.6 KiB
Markdown
Raw Permalink 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.

# 语音协议广播测试脚本
`adb shell am broadcast` 形式的联调脚本集合,覆盖 [可行性评估文档](../../../docs/2026-08-22-语音影视接入可行性评估.md) §6.1 中定义的统一协议(`action=com.pukka.jiecheng.action.VOICE_COMMAND`),用于在没有第三方语音 App 时手工驱动 voice 模块。
> 适用范围:`bash`(Git Bash 即可)。脚本里所有路径用 Unix 风格。
## 1. 目录结构
```
test/voice_helper/
├── lib/
│ └── common.sh # 公共函数:payload 构造 / 广播发送 / 应用级操作
├── jump_film.sh # 单片跳转 JUMP/FILM
├── jump_category.sh # 分类跳转 JUMP/CATEGORY
├── search.sh # 语音搜索 SEARCH
├── control.sh # 播放控制 CONTROL/<action>
├── cold_start.sh # 冷启动单片跳转(force-stop + 投递 + 拉起)
├── throttle_test.sh # 2 秒内连续投递同类命令(验证节流)
├── security_test.sh # 非白名单 sourceApp 投递(验证签名校验)
├── listen_callback.sh # 反向广播回调监听(adb logcat)
├── run_all.sh # 顺序执行全部用例
└── README.md
```
## 2. 协议约定(与文档 §6.1 一致)
```
action: com.pukka.jiecheng.action.VOICE_COMMAND
permission: com.pukka.jiecheng.permission.VOICE_COMMAND
component: com.pukka.jiecheng/.voice.receiver.VoiceCommandReceiver
extras:
requestId string 第三方生成的请求 ID,回传时带回
sourceApp string 第三方包名
sourcePlatform string 第三方平台标识(用于选择 VendorAParser/BParser)
commandType string JUMP / SEARCH / CONTROL
payload string JSON,业务字段
callbackAction string 反向广播 action,由第三方传入
timestamp long 毫秒
```
`payload` 按 `commandType` 分支:
| commandType | payload 字段 |
|---|---|
| `JUMP` | `jumpType` (`FILM`/`CATEGORY`/`ACTOR`/`DIRECTOR`) + 对应 `*Id`/`*Name`,可带 `autoPlay` |
| `SEARCH` | `filmName` / `actorName` / `directorName` / `category` / `unionStyle` / `region` / `releaseDate` |
| `CONTROL`| `action` (`PLAY`/`PAUSE`/`FULLSCREEN_ENTER`/`FULLSCREEN_EXIT`/`SEEK_FORWARD`/`SEEK_BACKWARD`/`SEEK_TO`/`PREV`/`NEXT`/`SELECT_INDEX`/`PAGE_NEXT`/`PAGE_PREV`/`GOTO_PAGE`) + `seconds` / `index` / `page` |
## 3. 快速开始
```bash
# 设备已连接 adb 后:
cd test/voice_helper
# 单片跳转(默认 filmId=film-demo-001 / autoPlay=true)
./jump_film.sh
# 自定义参数
./jump_film.sh film-12345 "我的影片" true
# 分类跳转
./jump_category.sh cat-action "动作片"
# 语音搜索
./search.sh "流浪地球"
./search.sh "流浪地球" "吴京"
# 播放控制
./control.sh PAUSE
./control.sh SEEK_FORWARD seconds=10
./control.sh SEEK_TO seconds=300
./control.sh SELECT_INDEX index=3
./control.sh GOTO_PAGE page=2
# 冷启动(force-stop → 投递 → 拉起 MainActivity)
./cold_start.sh
# 2 秒内连续 5 次 PAUSE,验证节流
./throttle_test.sh PAUSE 5
# 非白名单 sourceApp 投递(验证拦截)
./security_test.sh com.attacker.malicious
# 反向广播监听(需 voice 模块按 tag 打印回调日志,tag 默认 VoiceCommand)
./listen_callback.sh # 监听全部
./listen_callback.sh vt-1756000000-12345 # 只过滤指定 requestId
# 一键全量
./run_all.sh
```
## 4. 环境变量
| 变量 | 默认值 | 说明 |
|---|---|---|
| `ACTION_VOICE_COMMAND` | `com.pukka.jiecheng.action.VOICE_COMMAND` | 广播 action |
| `PERMISSION_VOICE` | `com.pukka.jiecheng.permission.VOICE_COMMAND` | 协议权限 |
| `RECEIVER_COMPONENT` | `com.pukka.jiecheng/.voice.receiver.VoiceCommandReceiver` | 显式组件 |
| `MAIN_ACTIVITY_COMPONENT` | `com.pukka.jiecheng/.MainActivity` | 冷启动入口 |
| `TEST_APP_PKG` | `com.pukka.jiecheng` | 应用包名 |
| `DEFAULT_SOURCE_APP` | `com.test.voicehelper` | 模拟第三方包名 |
| `DEFAULT_PLATFORM` | `vendorA` | 模拟平台 |
| `DEFAULT_CALLBACK_ACTION`| `com.test.voicehelper.action.VOICE_CALLBACK` | 反向广播 action |
| `TEST_REQUEST_PREFIX` | `vt-` | requestId 前缀 |
| `SKIP_PERMISSION_CHECK` | `0` | 开发期临时绕开 signature-level permission 校验时置 1 |
| `LOG_TAG` | `VoiceCommand` | `listen_callback.sh` 监听的 logcat tag |
示例:自定义第三方包名
```bash
TEST_REQUEST_PREFIX=demo- DEFAULT_SOURCE_APP=com.xiaomi.voice ./jump_film.sh
```
## 5. 关于 `signature-level permission`
文档 §6.2 规定 Receiver 使用自定义 `signature-level permission`(`com.pukka.jiecheng.permission.VOICE_COMMAND`)。`adb shell` 默认以 `shell` 用户身份投递,**不持有第三方签名权限**,广播会被系统直接丢弃。
联调期三种处理方式:
1. **临时降级(推荐)**:在 `app/build.gradle` 给 `debug` flavor 注入 `manifestPlaceholder`:
```groovy
debug {
manifestPlaceholders = [voiceProtectionLevel: "normal"]
}
release {
manifestPlaceholders = [voiceProtectionLevel: "signature"]
}
```
然后在 `AndroidManifest.xml`:
```xml
<permission
android:name="com.pukka.jiecheng.permission.VOICE_COMMAND"
android:protectionLevel="${voiceProtectionLevel}" />
```
2. **拷贝脚本到端内**:在应用内临时放一个 `BroadcastSender` Activity 直接发广播,绕过 shell 权限。
3. **改 adb 用户**:通过 `adb root` 切到 root 身份,仅在 userdebug 镜像生效。
脚本本身不强制任何一种处理,遇到权限拦截请按上面方式放开。
## 6. 验证 checklist(对应文档 §12)
联调完成后逐项打勾:
- [ ] 应用未启动时第三方冷启动并执行命令(`cold_start.sh`)
- [ ] 应用未激活时被守卫拦截,回传 `DEVICE_NOT_ACTIVATED`
- [ ] 正在播放时收到搜索 / 分类命令先退出再跳转
- [ ] 2 秒内连续多次控制命令只保留最后一条(`throttle_test.sh`)
- [ ] 第三方收到成功 / 失败回传(`listen_callback.sh` 配合 logcat)
- [ ] `SELECT_INDEX` / `GOTO_PAGE` 在播放页列表中正确选中
- [ ] 白名单外的 `sourceApp` 被拦截、不回传(`security_test.sh`)
## 7. 调试技巧
```bash
# 查看应用包内注册的 Receiver
adb shell dumpsys package com.pukka.jiecheng | grep -i receiver
# 查看设备上所有待发广播
adb shell dumpsys activity broadcasts
# 查看最近一次 am broadcast 的返回结果(带 requestId 过滤)
adb shell am broadcast -a com.pukka.jiecheng.action.VOICE_COMMAND -n ... --es requestId probe
# 实时过滤 voice 模块日志
adb logcat -v threadtime VoiceCommand:V VoiceCommandLogger:V "*:S"
```