OneTHU 宣传片 · 自动化演示流程(Demo Flow)¶
最后更新:2026-09-22 22:57
本文是可直接照着执行的拍摄剧本:分镜、节奏参数、环境准备、录制命令、剪辑衔接。
执行体在 tools/demo-flow/(flow.mjs 分镜驱动 + cdp.mjs 连接层)。
0. 设计原则(为什么这么做)¶
| 原则 | 落地方式 |
|---|---|
| 呼吸感节奏 | 每次转场/新页加载后停 1.5–2.0s;同页动作之间 220–420ms 抖动延迟(不是固定值,避免机械感)。参数集中在 flow.mjs 的 PACE,改一处即可整体调快慢。 |
| 聚焦爽点 | 不从注册/授权/设置切入:开场即「今日概览」,第二镜就是 OH 一句话直达(自然语言 → 结构化结果卡片),随后作业、成绩、校园卡、寻迹。 |
| 顺畅轨迹 | 滚动/翻页用多段小步 + 末段减速(scrollSteps/scrollMs),避免骤停骤起,录屏帧率更稳。 |
| 画面纯净 | --prep 统一环境:勿扰、固定亮度、常亮、竖屏锁、状态栏演示模式(时间 09:41 / 满电 / 满信号 / 隐藏通知)、冷启动回首页。 |
驱动方式:WebView DevTools 协议(CDP)。原因:本应用 WebView 不向 uiautomator 暴露
可访问性节点(dump 出来只有一个空 WebView),而硬编码坐标换设备/换字号必崩。CDP 直接读渲染
进程里的真实 DOM(文字、坐标、滚动),点击走 Input.dispatchMouseEvent(可信事件)。
连接靠 adb forward tcp:9222 localabstract:webview_devtools_remote_<pid>。
1. 分镜表¶
| # | 分镜 | 观众看到什么 | 主要动作 | 建议时长 |
|---|---|---|---|---|
| 1 | 开场:今日概览 | 课表、未交作业、近三日截止同屏;卡片排布与留白 | 首帧静置 → 下滚 380px → 静置 → 回滚 | 8–10s |
| 2 | 爽点:OH 一句话直达 | 灵动岛展开 → 逐字输入「明天图书馆哪有空座?」→ 结构化结果卡片出现 | 点胶囊 → 输入 → 回车 → 结果静置 2.6s | 12–14s |
| 3 | 作业:一屏管全部 | 网络学堂/雨课堂/OJ 合并后的状态分组;行内「忽略/提醒」 | 进入全部作业 → 下滚 560px → 静置 → 回滚 → 返回 | 12–14s |
| 4 | 信息页:成绩与考试 | 图表与统计(信息聚合的可视化美感) | 进入信息 → 成绩 → 下滚 → 静置 → 返回 | 10–12s |
| 5 | 生活页:校园卡余额与流水 | 余额大数字、近 30 天消费、逐笔流水(与桌面小组件同源) | 进入生活 → 校园卡 → 静置 2.1s → 下滚 → 返回 | 12–14s |
| 6 | 寻迹:日程在地图上串起来 | 带地点的今日日程 + 地图,「去哪、多久」 | 进入寻迹 → 静置 → 下滚 → 返回 | 10–12s |
| 7 | 收尾:桌面小组件 | 回到桌面,今日日程 / 校园卡小组件在应用之外继续工作 | 按 HOME → 静置 | 6–8s |
分镜 3–6 的入口文案(「全部作业」「信息」「成绩」「生活」「校园卡」「寻迹」)都写成
optional:找不到就跳过而不是中断——不同布局/字号下入口位置会变,脚本按文字找。 开录前用--scene=N逐镜补录,比全片重录省时间。
2. 环境准备(录制前,一次)¶
它做这些事(个别 ROM 不支持会静默跳过):
adb shell settings put global sysui_demo_allowed 1 # 允许状态栏演示模式
adb shell am broadcast -a com.android.systemui.demo -e command enter \
-e time 0941 -e battery 100 -e battery_charging true \
-e network wifi -e wifi show -e mobile hide -e notifications hide
adb shell settings put global zen_mode 1 # 勿扰:挡掉通知横幅
adb shell settings put system screen_brightness 180 # 亮度固定,避免录制中跳动
adb shell settings put system accelerometer_rotation 0 # 竖屏锁定
adb shell svc power stayon true # 常亮
adb shell am force-stop app.onethu.demo && adb shell monkey -p app.onethu.demo -c android.intent.category.LAUNCHER 1
手动确认(各 ROM 差异):没有悬浮球/录屏图标、没有输入法候选条、没有系统更新弹窗; 若状态栏仍显示真实时间或通知,说明该 ROM 不支持演示模式 → 退而求其次用沉浸式隐藏:
adb shell settings put global policy_control immersive.status=app.onethu.demo # 只藏状态栏
# 收尾:adb shell settings put global policy_control null
应用侧已经按系统栏 inset 垫好内容 padding(插件
applyContentInsets),所以无论状态栏 显示、隐藏还是沉浸式,顶栏都不会被压住——这也是 demo 版此前被压住的那个 bug 的修复。
2.5 动设备的边界(重要)¶
- 默认什么都不动:
--all/--scene=N跑完停在当前页面,不按 HOME、不改设置。 需要回桌面收尾时才加--end-home(分镜 7 自己会按 HOME)。 - 只有
--prep会动系统:改勿扰/亮度/常亮/方向锁 +force-stop应用冷启动。 录制前跑一次即可,日常别随手跑(正在用手机的人会觉得「应用被划走了」)。 --cleanup复位:退出演示模式、关勿扰、恢复自动旋转。- 连接层在应用没起来时会拉起它(不会杀它)。
3. 录制¶
首选 scrcpy(实时可见、可直接停、录制与画面一致):
scrcpy --no-audio --max-size=1920 --max-fps=60 --bit-rate=24M \
--stay-awake --window-title="OneTHU Demo" \
--record=OneTHU-demo-$(date +%m%d-%H%M).mp4
--no-audio:应用演示不需要设备音频,BGM/音效在剪辑里加。--max-size=1920 --max-fps=60:手机 1264×2800 缩到 1080p 竖向,60fps 保证滑动顺滑。--stay-awake:与svc power stayon双保险。
备选(无 scrcpy 时):
adb shell screenrecord --size 1264x2800 --bit-rate 24M --time-limit 180 /sdcard/demo.mp4
adb pull /sdcard/demo.mp4 .
执行顺序:
node tools/demo-flow/flow.mjs --prep # 1. 环境
scrcpy ... --record=demo.mp4 & # 2. 开始录
sleep 3 # 3. 留 3 秒黑场/首页静置给剪辑余量
node tools/demo-flow/flow.mjs --all # 4. 跑分镜(脚本自己控制节奏)
# 5. 停止录制(Ctrl-C scrcpy)
node tools/demo-flow/flow.mjs --cleanup # 6. 环境复位
剪辑节拍表:每次动作都写进 /tmp/onethu-demo-beats.jsonl({t, scene, action, text, x, y}),
剪辑时按时间戳对齐——哪一秒点了什么、哪一秒开始静置,一目了然:
# 把节拍表转成「分镜 → 起始秒」清单,直接当剪辑标记
node -e 'const l=require("fs").readFileSync("/tmp/onethu-demo-beats.jsonl","utf8").trim().split("\n").map(JSON.parse);
const t0=l[0].t; let cur="";
for(const r of l){ if(r.action==="分镜开始"){cur=r.title; console.log(((r.t-t0)/1000).toFixed(1)+"s ▶ "+r.title);} }'
4. 剪辑建议¶
- 卡点:每个分镜的「静置聚焦」段就是天然停顿点,转场放在那里,别在滑动中间切。
- 加速:联网加载段(OH 结果、成绩页)可以在剪辑里 1.5×,但要保留前后各 0.4s 原速。
- 常用 ffmpeg:
# 裁掉开头黑场
ffmpeg -ss 3 -i demo.mp4 -c copy demo-trim.mp4
# 竖向 1080×1920 规范化(保留整屏,两侧不裁)
ffmpeg -i demo-trim.mp4 -vf "scale=1080:-2,pad=1080:1920:(ow-iw)/2:(oh-ih)/2:black" -c:a none out.mp4
# 首尾 0.4s 淡入淡出
ffmpeg -i out.mp4 -vf "fade=t=in:st=0:d=0.4,fade=t=out:st=29.6:d=0.4" -c:a none final.mp4
5. 数据与身份¶
- 用 demo 包(
app.onethu.demo)录制:数据已脱敏(成绩/姓名/学号按口径替换), 且与正式版可同机共存,不影响日常使用。 - 录制前登一次 demo 包并让它把数据拉全(首页、作业、成绩、校园卡各页各进一次), 这样开录时是热数据,不会拍到骨架屏。
- 反复补录时不必清数据:
--prep只做冷启动,登录态与缓存都保留(清数据会导致未登录)。
6. 已知问题与对应¶
| 现象 | 处理 |
|---|---|
| demo 版顶栏被状态栏压住 | 已修:系统栏 inset 由插件垫成内容 padding(applyContentInsets),任何生成工程都对齐 |
| 预览在 Windows 上白屏 | 已知问题:Windows 文件预览暂不可用,界面直接给「下载 / 另存为」(不尝试渲染) |
| ColorOS 上小组件放不上桌面 | 已知问题:放置路径已统一为「先落空白卡片、点它再配置」,但 ColorOS 仍未通过 |
| 录到的页面是上次停留页 | --prep 会 force-stop 后冷启动;分镜 1 假设当前在首页 |
7. 手动录制速查(不想用自动脚本时)¶
这台测试机(Honor PPG-AN00,1264×2800 @560dpi)的实测数值: 状态栏高 135px(
InsetsSource type=statusBars frame=[0,0][1264,135]), 手势条 78px;内容区 = 1264 × 2587 @ (0,135)。 (与 CDP 量到的 WebView 视口 739dp × 3.5 = 2586.5px 互相印证。)
7.1 隐藏状态栏:三条路,按可靠性排序¶
① scrcpy 裁剪录制(最稳,不改系统设置)
scrcpy --no-audio --max-size=1920 --max-fps=60 --bit-rate=24M --stay-awake \
--crop=1264:2587:0:135 \
--record=OneTHU-demo-$(date +%m%d-%H%M).mp4
--crop=宽:高:x:y:裁掉顶部 135px 状态栏与底部 78px 手势条 → 成片里根本没有状态栏,
不需要改任何系统设置,也不怕 ROM 不配合。
② 沉浸式隐藏(改设置,部分 ROM 有效)
adb shell settings put global policy_control immersive.status=app.onethu.demo
# 若无效试:immersive.full=app.onethu.demo
# 收尾:adb shell settings put global policy_control null
③ 后期裁掉
7.2 一次性环境(手动,建议跑一遍)¶
# 状态栏演示模式:固定 09:41、满电、满信号、隐藏通知(不隐藏状态栏时的"体面版")
adb shell settings put global sysui_demo_allowed 1
adb shell am broadcast -a com.android.systemui.demo -e command enter \
-e time 0941 -e battery 100 -e battery_charging true \
-e network wifi -e wifi show -e mobile hide -e notifications hide
adb shell settings put global zen_mode 1 # 勿扰,挡通知横幅
adb shell settings put system screen_brightness_mode 0
adb shell settings put system screen_brightness 180 # 亮度固定
adb shell settings put system accelerometer_rotation 0 && adb shell settings put system user_rotation 0
adb shell svc power stayon true # 常亮
收尾复位:
adb shell am broadcast -a com.android.systemui.demo -e command exit
adb shell settings put global sysui_demo_allowed 0
adb shell settings put global zen_mode 0
adb shell settings put system accelerometer_rotation 1
adb shell svc power stayon false
7.3 手动操作时的节奏清单¶
| 分镜 | 手动动作 | 停留 |
|---|---|---|
| 1 今日概览 | 冷启动进首页 → 慢速下滚一屏 → 回滚 | 首屏 3s,每次滚动后 2.5s |
| 2 OH 直达 | 点底部胶囊 → 不点输入框(避免键盘入镜)→ 直接用系统「粘贴」或先在外面写好再粘 → 回车 → 等结果出现 | 展开后 1.5s,结果出现后 2.5s |
| 3 作业 | 首页点「未交作业」→ 滚一屏 → 返回 | 每屏 2s |
| 4 成绩 | 打开导航菜单 → 信息 → 成绩 → 滚一屏 | 2s |
| 5 校园卡 | 导航 → 生活 → 校园卡 → 滚一屏 | 余额卡停留 2.5s |
| 6 寻迹 | 导航 → 寻迹 → 滚一屏 | 2s |
| 7 收尾 | 回桌面(展示小组件) | 2.5s |
避免键盘入镜的两条路:① 用 scrcpy 裁剪时手动点输入框打字也没关系——键盘在底部, 但会挡住内容;② 更省事:先在备忘录里写好问题 → 复制 → 在应用里长按输入框粘贴 → 回车。 (自动脚本走的是「不聚焦注入文字」,所以它从不弹键盘。)