Skip to content

feat(android): 重构播放系统,支持移动端频谱与原生队列 - #23

Merged
Re-BeiChen merged 1 commit into
SPlayer-Dev:devfrom
Shomi-FJS:Webview-FIX
May 22, 2026
Merged

Re-BeiChen merged 1 commit into
SPlayer-Dev:devfrom
Shomi-FJS:Webview-FIX

Conversation

@Shomi-FJS

Copy link
Copy Markdown

📌 变更类型

  • ✨ feat — 新功能
  • 🐞 fix — Bug 修复
  • ♻️ refactor — 重构,不改变外部行为
  • ⚡ perf — 性能优化

📝 变更说明

本次 PR 聚焦于 Android 原生播放链路自治化 与 频谱 / 进度 / 封面 等周边性能问题 的修复,主线目标是 WebView 在后台被冻结或主线程长时间繁忙时,Android 端仍能完成自主切歌、续播、媒体会话同步与频谱展示。

1. Android 原生播放队列自治(核心)

  • JS 端推送 ±100 = 201 首滑动窗口到 Java(buildAndroidWindowTracks),覆盖最大 200 首后台续播,payload ~70KB 主线程无感知。
  • Java 端 PlaybackQueue 自主推进:advanceRaw / backRaw 跳过 skipSong,窗口完整覆盖全局列表(≤201 首)时自治 ALL wrap;窗口边缘耗尽则 emit requestUrls 让 JS 补窗。
  • 修复异步 URL 解析竞态:在 playFromQueue / load / cleanup 入口统一自增 resolveTokenCounter,过期 token 回调直接丢弃;清理过期 pendingResumeAfterRefill 避免补窗误续播。
  • 修复 ENDED 续播缺口:窗口耗尽且 hasNextOutsideWindow=true 时拦截 ENDED,等下一次 updateQueueContext 拿到新窗口后立即 advance + playFromQueue,弥补 JS 不主动 play 的链路缺口。
  • personalFM 退化为 radius=0,单首推进语义不破坏。

2. Android FFT 频谱采集

  • 新增 FftAudioProcessor 接入 ExoPlayer 自定义 RenderersFactory,音频线程只写 snapshot buffer,主线程做 base64 编码 + IPC emit,避免阻塞音频回调。
  • 支持多实例设计,为未来 Automix(双轨 crossfade)预留扩展。
  • TS 端 AndroidNativeAudioPlayer.enableVisualizer 串行化,原生调用失败时回滚 flag 避免锁死。

3. 频谱渲染拆分与 z-index 修复

  • 桌面端 / 移动端频谱组件解耦,修复频谱画布与播放器 UI 的 z-index 冲突。
  • 频谱绘制节流至 30Hz,改为单 Path2D 批绘减少 GPU 状态切换。
  • visibilitychange 驱动采集 / 绘制启停,后台与锁屏不再无谓消耗 CPU / 电量。

4. 歌词存储优化

  • music-store 的 persist.pick 收窄到 playSong / playPlaylistId / personalFM / dailySongsData,songLyric 不再持久化,每次切歌少写 100-500KB 逐字 yrcData JSON。
  • syncFloatingLyricData 用 requestIdleCallback 推迟 JSON.stringify,且只在 showDesktopLyric=true 时执行。
  • setupSongUI 改 statusStore.$patch 合并 7-8 个独立 setter 为一次序列化。

5. 播放进度更新重构

  • 仅在「播放中 + 页面可见」时启动 60Hz rAF,暂停 / 不可见时停 rAF 并同步一次。
  • 进度链路在缓冲期间保持存活,避免 UI 在 buffering 时假死等待。

6. 动态封面修复

  • video 增加 poster / playsinline / preload / disablepictureinpicture,新增 error / stalled 事件兜底,失败时清理资源避免花屏与原生播放按钮占位。
  • 动态封面 URL 升级 HTTPS 避免 Mixed Content。
  • 修正 IPC 返回类型,完善本地封面资源清理。

7. 周边

  • getCoverColor 采样降至 32×32 + requestIdleCallback 调度 + LRU 缓存,切歌时主线程更顺滑。

📱 影响范围

  • 🎵 播放引擎 / 音频
  • 📝 歌词 / 桌面歌词
  • 🔔 通知栏 / MediaSession
  • 🎨 UI / 主题 / 布局
  • 📱 Capacitor / 原生 Android 代码

✅ 自检清单

  • 本 PR 目标分支为 dev
  • 本地已执行 pnpm lint 且无 warning
  • 本地已执行 pnpm typecheck 且无报错
  • 已在 至少一台真机 上构建并验证关键路径
  • UI 改动已兼顾 手机竖屏 + 平板横屏 两种布局
  • 新增 / 修改的文案使用中文,与项目整体风格一致
  • 未引入不必要的依赖 / 大体积资源
  • 未修改签名密钥 / CI Secrets 相关文件

🧪 测试方式

  1. 后台自治续播:构造 ≤200 首播放列表,进入播放后将应用切到后台并锁屏 ≥5 分钟(确保 WebView 被冻结),验证通知栏切歌按钮 / 自动续播 / ALL wrap 正常。
  2. 窗口边缘补窗:构造 >200 首列表,播放到接近窗口右缘时观察 requestUrls → JS 补窗 → Java 续播链路是否无缝。
  3. 频谱 & 锁屏:开启频谱可视化,分别在前台、后台、锁屏、息屏场景验证频谱采集启停与 CPU 占用变化。
  4. 切歌流畅性:连续点击下一首 ≥10 次,验证不再出现按钮无响应 / UI 跳跃 / 进度条假死。
  5. 动态封面:切到含动态封面的歌曲,断网或人为返回 4xx 验证错误兜底(不出现花屏与原生播放按钮占位)。
  6. 类型 & Lint:pnpm lint 与 pnpm typecheck:web 在改动文件无新增错误。

💬 其他说明 (选填)

  • 窗口大小取舍:±100(201 首)是性能甜点位,payload ~70KB / 序列化 ~8ms,远超日常需求;列表 >201 首时仍走 JS 补窗,行为正确但补窗瞬间会有一次 IPC 推送。如需放大到 ±150 / ±250,建议先做 WindowTrack 字段瘦身或增量 diff 推送。
  • Automix 兼容:FftAudioProcessor 多实例设计已为未来双 ExoPlayer crossfade 预留扩展位,setAudioProcessors 传数组而非单元素。
  • 既有类型错误:pnpm typecheck:web 仍残留 58 个旧错误,集中在本 PR 未触及的 19 个文件

- 新增Android原生播放队列自治,WebView冻结时仍可自主切歌
- 实现Android端FFT频谱采集,支持移动端音乐频谱显示
- 拆分频谱渲染到桌面端与移动端,修复z-index冲突
- 优化歌词存储逻辑,避免逐字歌词阻塞主线程
- 重构播放进度更新逻辑,适配后台与可见性状态
- 修复动态封面加载问题,优化兼容性与错误兜底
@Re-BeiChen
Re-BeiChen merged commit 6300673 into SPlayer-Dev:dev May 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants