Files
jiecheng-business/test/voice_helper/README.md

167 lines
6.6 KiB
Markdown
Raw Normal View History

# 语音协议广播测试脚本
`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"
```