☰
锁屏也能听 YouTube:NouTube 后台播放功能的深度实现指南
2026/10/14 16:42:20 网站建设 项目流程

【免费下载链接】NouTube

YouTube and YouTube Music in a single app. No ads, plays in the background.

项目地址:https://gitcode.com/gh_mirrors/no/NouTube
点击查看免费下载

NouTube 是一款把 YouTube 和 YouTube Music 装进同一个 App 的跨平台应用,核心卖点就一句话:无广告、支持后台播放(锁屏也能听)。本文带你拆解它的后台播放功能到底是怎么实现的——不需要 Premium 会员,熄屏、锁屏、切到其他 App,声音照样不中断。

一、难点在哪:YouTube 为什么"故意"暂停?

先看背景。NouTube 并不是自己写了一个播放器,而是用WebView 包裹 m.youtube.com 和 music.youtube.com,再注入脚本完成增强(见 README.md 的 "How it works"):

Wrap https://m.youtube.com and https://music.youtube.com in Android webview, inject code to block ads, hook playback controls and support playing in background.

问题就出在"包裹网页"这件事上。YouTube 移动端网页有一条刻意的规则:

  • 一旦页面"不可见"(切后台、锁屏),网页版就暂停播放,因为免费用户没有音频后台播放权限;
  • 长时间播放还会弹出"Video paused. Continue watching?"的空闲确认框,点不点都容易打断播放。

所以 NouTube 的后台播放,本质上是在和 YouTube 的这条规则"斗智斗勇"。它的思路分三层,我们一层层看。

二、第一层:让网页"以为"自己一直亮着

在 Android 端,WebView 的可见性由系统回调决定。NouTube 在 NouTubeView.kt 里重写了onWindowVisibilityChanged,永远向上报告VISIBLE——这样 YouTube 网页永远检测不到自己"被切走",自然不会触发暂停。

iOS 的 WKWebView 没有类似的可见性钩子,网页会在 App 退后台的一瞬间被标记为 hidden。NouTube 用了一段注入脚本"覆盖"这个状态(NouTubeView.swift):

WKWebView flips the page to hidden the moment the app leaves the foreground, and YouTube pauses mobile web as soon as it sees that. The Android view keeps the page visible from the native side instead; this is the same trick for WebKit.

但这里有个精巧的设计:页面被骗了,App 自己没骗。真实的可见性状态会被同步到一个全局变量window.NouTubeBackground里——Android 端在 NouTubeView.kt 的容器回调里写入,iOS 端监听didEnterBackground/willEnterForeground通知后写入(NouTubeView.swift)。

这个"真话通道"是第二层防护的基础。

三、第二层:后台自动续播守卫(核心)

光"骗过"页面还不够。YouTube 还有另一条路:它的Media Session 处理器和空闲检测依然可能在后台把视频暂停掉。用户这时根本摸不到页面,播放就断了。

为此 NouTube 写了一个注入脚本 content/background-guard.ts,它的职责是:后台期间,凡是"不是用户要求的"暂停,一律自动恢复。逻辑拆解如下:

暂停来源如何识别守卫的对策
用户自己暂停(通知栏、蓝牙耳机按键、睡眠定时器)包装NouTube.pause()打标记appPaused绝不恢复,尊重用户
iOS 锁屏/控制中心操作提前 hookmediaSession.setActionHandler(guardMediaSessionHandlers)视为用户行为,不恢复
来电、其他 App 抢占音频原生侧canAutoResume()返回 false彻底停住,等用户手动恢复
YouTube 自己的后台暂停以上都排除了 → 只剩这一种可能自动点掉弹窗并playVideo()续播

实现上是一个每 5 秒一次的轮询(background-guard.ts):读取movie_player的播放状态,如果"之前在播 + 现在暂停了 + 不是用户所为 + 不是音频中断",就先尝试点掉ytmusic-you-there-renderer的确认弹窗,再调用playVideo()。连续 3 次恢复失败就停止尝试,避免和系统策略"对打"。

细节上还有几处值得学习的工程判断(源码注释写得非常直白):

  • 同步记录前台暂停:pause事件监听用捕获阶段,防止"用户刚暂停就切后台"的竞态被误判成 YouTube 的暂停;
  • 弹窗只点"单按钮"的情况:多按钮弹窗不瞎猜,反正playVideo()也能续播;
  • iOS 的 Media Session 要抢先 hook:YouTube 在DOMContentLoaded之前就注册了自己的处理器,所以 content/main.ts 在 document 一开始就调用guardMediaSessionHandlers()。

四、第三层:原生外壳——通知栏与锁屏控制

网页"活下来"之后,用户体验要靠原生层来补齐。

Android:NouService.kt 是一个前台服务(Foreground Service),负责:

  • 常驻媒体通知:标题、作者、封面缩略图,外加播放/暂停、上一首、下一首、快退/快进、倍速切换按钮(通知上直接循环 1x→1.25x→1.5x→1.75x→2x);
  • 所有按钮点击都通过evaluateJavascript("NouTube.xxx()")转译成页面内播放器的操作;
  • 监听拔耳机(ACTION_AUDIO_BECOMING_NOISY)和蓝牙耳机断连,自动暂停;
  • 最硬核的部分在ensureForeground()(NouService.kt):有真机实测发现系统会在 App 后台约 18 分钟后静默撤销服务的前台状态,之后 WebView 渲染进程就成了后台清理对象。NouTube 的对策是:只要还在播放,每分钟重新断言一次前台状态,把通知栏重新挂上去,确保渲染进程不会被杀。

iOS:配置里只有一行关键声明,app.config.ts 的UIBackgroundModes: ['audio'],注释写得很直白——"The player keeps going with the screen off and on the lock screen."。锁屏和控制中心的卡片则由 NouNowPlaying.swift 驱动:设置AVAudioSession为.playback类别并激活,同步标题/作者/进度/封面到MPNowPlayingInfoCenter;如果通话或其他 App 抢占了音频,中断结束后还会自动重新激活会话,避免"从此静音"。

五、用户视角:这些实现落地成了什么体验?

把三层拼起来,普通用户得到的是:

  • 🎧锁屏听歌:播放中直接按电源键,通知栏/锁屏卡片上继续控制;
  • ⏩通知栏倍速:不打开 App 就能切播放速度;
  • 🎒拔耳机自动暂停:防外放社死;
  • 🌙睡眠定时器:原生层精确到毫秒计时,到点自动NouTube.pause()(NouService.kt),而且这种暂停守卫脚本绝不"好心"恢复;
  • 🔁抗 YouTube 空袭:后台几小时也不会被"Continue watching?"打断。

六、关键文件清单(延伸阅读)

  • content/background-guard.ts —— 后台自动续播守卫,全项目"斗智"逻辑的核心;
  • content/main.ts —— 注入脚本入口,按顺序装配各项能力;
  • modules/nou-tube-view/android/src/main/java/expo/modules/noutubeview/NouService.kt —— Android 前台服务与媒体通知;
  • modules/nou-tube-view/android/src/main/java/expo/modules/noutubeview/NouTubeView.kt —— WebView 可见性伪造与 JS 桥;
  • modules/nou-tube-view/ios/NouTubeView.swift —— iOS 侧可见性脚本注入;
  • modules/nou-tube-view/ios/NouNowPlaying.swift —— 锁屏/控制中心 Now Playing 卡片;
  • app.config.ts —— iOSUIBackgroundModes与 Android 权限声明。

七、小结

NouTube 的后台播放不是某一个 API 的功劳,而是一套组合拳:伪造网页可见性绕过 YouTube 的暂停规则,后台守卫脚本精准区分"谁按的暂停键"并自动续播,原生前台服务/音频会话兜住系统杀进程和锁屏体验。想给 Web 应用做播放增强,这套"页面层欺骗 + 行为归因 + 原生兜底"的三层架构,值得直接抄作业。

【免费下载链接】NouTube

YouTube and YouTube Music in a single app. No ads, plays in the background.

项目地址:https://gitcode.com/gh_mirrors/no/NouTube
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询