wallace-screen-app/docs/广告机实现方案.md

105 lines
5.2 KiB
Markdown
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.

# 华莱士门店电视广告机:一期实现方案
## 一期目标
交付一个 Android APK,安装在门店电视或广告屏上后始终横屏全屏运行。终端首次开机显示绑定二维码;门店通过小程序扫码完成设备与门店绑定;绑定完成后,终端按后台下发的顺序循环播放图片和视频广告。
一期不做终端侧人工操作、广告编辑或门店管理,这些能力全部由后台或小程序承接。
## 终端状态
1. **初始化**:生成并持久化唯一设备标识 `sn`。Android App 优先读取 DCloud 的 `plus.device.uuid`;它不可用时才生成应用级随机编号并保存在本地。
2. **待绑定**:二维码内容为完整 HTTPS 绑定链接,例如 `https://screen.example.com/bind?sn=WLS-xxx`。每 10 秒查询一次绑定状态。
3. **拉取节目单**:绑定成功后,获取门店信息、终端授权信息和广告节目单。
4. **播放中**:图片按 `duration` 停留,视频播放至结束;每项播放完毕后切换到下一项。
5. **刷新节目单**:完整播放一轮后重新拉取节目单;后台也可在响应中返回 `refresh_interval`,用于定时刷新。
6. **异常/离线**:保留最近一次有效节目单和媒体缓存;网络恢复后自动同步。没有可播放素材时显示简洁的门店品牌待机页。
## 建议接口约定
### 查询绑定状态
`GET /screen/v1/devices/{sn}/binding`
```json
{
"code": 200,
"data": {
"bound": true,
"store_id": "WALLACE-001",
"token": "terminal-token"
}
}
```
### 获取节目单
`GET /screen/v1/playlists/current?sn={sn}`
```json
{
"code": 200,
"data": {
"revision": "20260820-01",
"refresh_interval": 300,
"items": [
{
"id": "creative-001",
"type": "image",
"url": "https://cdn.example.com/creative-001.jpg",
"duration": 8,
"checksum": "sha256..."
},
{
"id": "creative-002",
"type": "video",
"url": "https://cdn.example.com/creative-002.mp4"
}
]
}
}
```
规则:`type` 仅允许 `image`、`video`;图片的 `duration` 单位为秒且必须大于 0;视频由其实际时长决定切换。节目单必须携带版本号和素材校验值,便于终端判断是否需要下载更新。
## 当前 Mock 实现
- 配置位于 `config/terminal.ts`,当前 `useMock: true`。
- 终端会生成 `WLS-` 前缀的 `sn`,并将 `bindPageUrl` 与 `sn` 拼成二维码内容。
- 待绑定页提供“模拟完成绑定”按钮,且默认 15 秒后自动模拟绑定,方便电视端演示。
- Mock 节目单为“图片 → 视频 → 图片”,完整播放一轮后重新读取节目单。
- Mock 阶段二维码图片由公共二维码服务渲染;正式发布前应替换为内置二维码组件,避免依赖第三方二维码服务。
- 后端就绪时,将 `useMock` 改为 `false`,并在 `services/terminal.ts` 的两个方法中接入绑定状态、节目单正式接口。
## 终端实现划分
- `services/device`:生成、读取和存储设备 `sn`;Android 优先使用系统稳定标识并派生应用设备号。
- `services/binding`:绑定状态轮询、终端令牌管理和门店信息读取。
- `services/playlist`:节目单请求、数据校验、版本比对和本地持久化。
- `services/media-cache`:下载媒体、校验 checksum、清理过期缓存,并始终保留当前节目单。
- `components/ScreenPlayer`:统一渲染图片、视频、加载失败占位和下一项预加载。
- `pages/index`:按终端状态装配“待绑定”和“播放”两个状态视图,不提供业务导航。
## 播放与可靠性规则
1. 切换前预加载下一张图片或下一个视频,避免黑屏。
2. 视频监听 `ended`、`error`、超时三种事件;失败时记录并跳过,不能阻塞整个节目单。
3. 单个素材连续失败 3 次后,本轮播放忽略该素材;下一次节目单更新后重新尝试。
4. 所有网络请求采用指数退避重试;无网络时继续播放已缓存内容。
5. 进入播放页后隐藏状态栏和导航栏,禁用旋转回竖屏,按 16:9 容器等比裁切显示。
6. 终端只展示必要状态:未绑定二维码、加载中、无可播放内容;不暴露接口地址、令牌或调试信息。
## 实施顺序
1. 对接绑定状态接口,完成设备号、二维码和轮询状态页。
2. 对接节目单接口,完成图片/视频顺序播放和整轮刷新。
3. 加入媒体预加载、离线缓存、失败跳过和网络恢复。
4. 在目标电视设备上验证横屏全屏、自启动、断网恢复、连续播放和 APK 签名发布。
## 需后台确认
- 绑定二维码最终使用的正式域名/小程序跳转规则。
- 设备与门店解绑、换店、禁用设备的接口和状态码。
- 节目单素材 CDN、视频格式上限、有效期和审核策略。
- 需要 Android 开机自启动和受控保活:APK 侧需由原生 Android Receiver/厂商白名单或 MDM 触发开机拉起;电视/机顶盒侧推荐纳入 MDM 的 kiosk(单应用)策略。仅申请 `RECEIVE_BOOT_COMPLETED` 权限不足以保证各品牌设备可自启动,必须在目标设备实测并按厂商策略配置。