☰
Myspoti 源码架构深度解析::api / :api-spotify / :host-cdp 三模块如何协作
2026/11/1 1:50:15 网站建设 项目流程

【免费下载链接】myspoti

Native Android client for Spotify, built with Jetpack Compose

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

Myspoti 是一个用 Jetpack Compose 打造的 Spotify 原生 Android 客户端,它的源码采用经典的"接口契约—平台实现—宿主环境"三层架构::api定义纯 Kotlin 接口,:api-spotify基于官方 Web Player 给出完整实现,:host-cdp则把同一套实现接到桌面 Chrome 上跑真实集成测试。本文带你快速读懂这三个模块各自负责什么、它们又是如何协作的。

🧩 项目总览:一个 Gradle 多模块工程

打开 base/settings.gradle.kts,可以看到工程一共声明了 7 个模块:

模块角色依赖关系
:appJetpack Compose UI 层→:host-android、:extensions
:host-androidAndroid WebView 宿主(BridgeHost的安卓实现)→:api-spotify
:host-cdp桌面 Chrome(CDP 协议)宿主 + 真机级集成测试→:api-spotify
:api-spotify用官方 Web Player 实现:api的全部接口→:api
:api纯 Kotlin 接口契约:数据模型 + 接口定义无 Android、无 Spotify 细节
:extensions/:extensions-cli扩展沙箱运行时与桌面调试器—

这张依赖表就是全文的骨架:箭头全部单向向下,UI 永远不直接碰 Spotify,Spotify 实现永远不知道自己跑在 WebView 还是 Chrome 里。

📐 第一层::api —— 只写契约,不写实现

:api是整个架构的地基。它的入口是一个总接口 MyspotiApi,聚合了 14 个领域:

interface MyspotiApi { val player: Player val search: Search val catalog: Catalog val library: Library val playlists: Playlists val home: Home val podcasts: Podcasts // ... devices、jam、blends、recents 等 }

以 Player 为例,它把播放域拆成play / pause / seek / setShuffle / addToQueue / setVolume等一组suspend函数,并用StateFlow暴露当前状态。整个模块只有接口和模型,没有任何 Android API、没有 OkHttp、没有一行 Spotify 细节——这正是它敢叫"契约"的原因:UI 面对的是:api,而不是某个具体实现。

🌐 第二层::api-spotify —— 在 Web Player 之上搭一座桥

SpotifyApi 是MyspotiApi的实现类,它的设计精髓是双通道数据流:

  • 读请求走 HTTP 直连:搜索、目录、主页等"只读"操作由SpotifyHttp直接请求 Spotify 服务器(页面 web token + 本地铸发的 client token),快且可并行;
  • 写操作与播放走 Bridge:播放控制、收藏写入、Connect、Jam 都通过页面内部的官方服务完成,由注入到 open.spotify.com 的player-bridge.js负责调用。

两个通道的交汇点是一个极小的接口 BridgeHost——它只要求宿主提供两样东西:向页面执行脚本(evaluate)和接收页面消息(messages)。请求/响应编解码则由 Bridge 完成。

此外,SpotifyApi.raw还保留了一个"逃生舱口":可以直接触达 Web Player 的全部 179 个 GraphQL 操作和 89 个页面服务,方便快速验证尚未类型化的能力(详见 api-spotify/README.md)。

🖥️ 第三层::host-cdp —— 让同一套代码跑在桌面 Chrome 上

这是最有意思的模块。:api-spotify只依赖抽象的BridgeHost,所以任何"能跑 Web Player 页面"的环境都可以当宿主:

  • 手机上:WebPlayerHost 用一个 Android WebView 加载 open.spotify.com,实现BridgeHost,并在shouldInterceptRequest里拦截广告音频;
  • 桌面上:CdpHost 通过 Chrome DevTools Protocol(CDP)WebSocket 连接启动调试端口的 Chrome,把Runtime.evaluate映射成evaluate、把Runtime.addBinding映射成messages。

于是开发者可以不用真机就进行全链路测试,LiveApiTest 就是靠它驱动一个真实登录的 Web Player 跑完整 API 回归:

google-chrome --user-data-dir=<profile> --remote-debugging-port=9222 # 登录一次 ./gradlew :host-cdp:test -Pcdp=http://localhost:9222

测试覆盖播放、搜索、目录、歌单、Jam 等全部领域,且每个用例都会还原自己修改的状态。

🔗 三模块协作:一条"播放"命令的完整链路

把三层拼起来,你点下播放按钮后发生的事情是:

  1. :app(UI)调用MyspotiApi.player.play(...)——它只认识:api里的接口;
  2. :api-spotify的SpotifyPlayer通过Bridge生成一次编号调用,交给BridgeHost.evaluate;
  3. :host-cdp或:host-android把脚本送进页面(Chrome 走Runtime.evaluate,手机走 WebView),页面里的player-bridge.js调起官方PlayerAPI开始播放;
  4. 页面把新的播放状态通过MyspotiHost.postMessage推回宿主,Bridge收到state消息后更新StateFlow,UI 自动刷新。

整条链路里,:api保证 UI 与实现解耦,:api-spotify保证业务逻辑与运行环境解耦,:host-cdp则让"实现 + 真实 Spotify"可以在桌面上被反复验证——三者各司其职,构成了这个开源项目最值得学习的架构范例。

✅ 小结

  • :api:纯 Kotlin 契约层,UI 唯一依赖(base/api/);
  • :api-spotify:契约的 Spotify 实现,HTTP 直连读 + Bridge 直写(SpotifyApi.kt);
  • :host-cdp:桌面 CDP 宿主,把同一实现接到 Chrome 上跑真机级测试(CdpHost.kt)。

想深入更多细节,建议按顺序阅读 base/api-spotify/README.md 和 docs/api/CAPABILITIES.md,它们分别覆盖了 Bridge 消息协议与全量能力清单。

【免费下载链接】myspoti

Native Android client for Spotify, built with Jetpack Compose

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

相关推荐

上一篇:财新周刊都来追问「AI 生成的课堂怎么教学」:OpenMAIC 破圈路线图
下一篇:Claude 知识工作插件开源:85+ 技能免费装,『效率翻倍』的说法到底靠不靠谱

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

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

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

立即咨询