# 华莱士门店电视广告机:一期实现方案 ## 一期目标 交付一个 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` 权限不足以保证各品牌设备可自启动,必须在目标设备实测并按厂商策略配置。