Morphe Patches架构深度剖析:150个补丁如何用patches与extensions两大模块组织
【免费下载链接】morphe-patchesMorphe Patches项目地址: https://gitcode.com/gh_mirrors/mo/morphe-patches
Morphe Patches 是一个面向 Android 应用(YouTube、YouTube Music、Reddit)的补丁工程,当前 v1.44.0 共提供150 个补丁。它的核心架构可以用一句话概括:patches模块负责"怎么打补丁",extensions模块负责"打进去的代码长什么样"。本文带你完整拆解这套组织方式。
150个补丁是怎么分布的
补丁数量来自官方 README.md 的补丁清单(由发布流程自动生成,对应机器可读的 patches-list.json):
| 目标应用 | 补丁数 | 补丁所在目录 |
|---|---|---|
| 📺 YouTube | 84 | patches/.../youtube/、extensions/youtube/ |
| 🎵 YouTube Music | 42 | patches/.../music/、extensions/music/ |
| 20 | patches/.../reddit/、extensions/reddit/ | |
| 🌐 通用(Universal) | 4 | patches/.../all/、extensions/all/ |
也就是说,补丁按"目标应用"分域,两个模块内部用完全对称的目录结构对应,找任何一个补丁都能一眼定位到它的两侧代码。
两大模块的分工:patches 管"怎么打",extensions 管"打什么"
🧩 patches 模块:用 Kotlin 编写的补丁定义
patches/下有447 个 Kotlin 文件,每个补丁定义都遵循统一模板:
- 声明补丁名称与描述(会同步到 README 与 patches-list.json)
- 声明依赖(
dependsOn)和兼容包(compatibleWith) - 在
execute { }块中定位目标代码并插入指令
定位代码靠的是Fingerprint(指纹)——按方法签名、访问标志、字节码指令序列"画像",而不是写死类名,这样 App 升级后依然能匹配到目标。例如 YouTube 进度条相关补丁的指纹集合:
Fingerprints.kt
目录按应用/功能域两级组织,如:
patches/src/main/kotlin/app/morphe/patches/ ├── all/ # 通用补丁:克隆应用、禁用商店更新等 ├── music/ # 歌词、交叉淡入、下载等 42 项 ├── reddit/ # 字体、广告、侧边栏等 20 项 ├── shared/ # 跨应用共享逻辑(主题、防篡改、PoToken…) └── youtube/ # 84 个补丁,细分到 seekbar、swipecontrols…📦 extensions 模块:真正注入 App 的代码
extensions/下有556 个 Java/Kotlin 文件,这些代码会被编译、混淆后塞进目标 APK,运行期由补丁插入的指令调用。它有 6 个子模块:
| 子模块 | 职责 |
|---|---|
all/ | 通用扩展,如修改安装包版本号 |
youtube/ | YouTube 补丁实现 + 设置界面(Settings.java) |
music/ | 音乐补丁实现,含歌词(46 个文件)、下载、打歌记录等 |
reddit/ | Reddit 补丁实现与设置界面 |
shared/ | 跨应用共享代码:环境检查、请求工具、主题、翻译 |
shared-youtube/ | YouTube 系共享能力:SponsorBlock、Rtd 点赞/点踩、OAuth2 等 |
此外各模块还带一个stub/目录(如 extensions/youtube/stub/),存放 Cronet、Litho 等目标 App 内部 API 的空壳类声明,让扩展代码在编译期就能"看到"这些类,而不需要依赖 App 本体。
一个补丁的完整旅程:两侧代码如何会师
以"禁用双击跳转章节"补丁为例,看一次完整协作:
- 补丁侧(DisableChapterSkipDoubleTapPatch.kt):先用 Fingerprint 在 App 字节码中找到目标方法,然后插入一条 smali 指令——
invoke-static { p1 }, Lapp/morphe/extension/youtube/patches/DisableDoubleTapActionsPatch;->disableDoubleTapChapters(Z)Z; - 扩展侧(DisableDoubleTapActionsPatch.java):提供一个静态方法
disableDoubleTapChapters(original),内部读取用户在 Morphe 设置里的开关值,返回最终结果。
┌─────────────────── patches(构建期) ───────────────────┐ │ Fingerprint 定位 → 插入 invoke-static 调用 → 注入开关设置项 │ └──────────────────────────┬──────────────────────────────┘ ▼ ┌─────────────────── extensions(运行期) ──────────────────┐ │ 静态方法读取 Settings 开关 → 返回改写后的布尔值 │ └──────────────────────────────────────────────────────────┘YouTube Music 的"交叉淡入"(Crossfade)功能则是更复杂的双播放器实现,其功能说明横幅也打包在补丁资源里,随补丁一起分发:
构建系统与配套文件
- 构建入口:settings.gradle.kts 声明了
app.morphe.patches插件(补丁框架),统一设置扩展命名空间app.morphe.extension和 ProGuard 混淆规则 extensions/proguard-rules.pro; - 发布产物:patches-bundle.json 记录版本号与下载地址,patches-list.json 是自动化生成的补丁元数据(名称、描述、依赖、兼容版本),供第三方工具消费;
- 历史档案:archive/ 保留了上游 ReVanced 工程的压缩包,NOTICE 与 LICENSE 说明了其 ReVanced 分支渊源与 GPLv3 附加条款。
总结:为什么这种组织值得借鉴
- 关注点分离——补丁逻辑(何时改、改哪里)与业务实现(改成什么样)完全解耦,新增一个功能 = 加一个
.kt补丁 + 一个静态方法; - 指纹驱动——靠字节码指纹而非硬编码定位,天然抗 App 小版本升级;
- 对称目录——
patches与extensions按应用一一对应,556 + 447 个文件依然可检索、可维护。
理解了这套"patches 定义 + extensions 实现"的双模块模式,你就能顺着任意一个补丁名,在两棵目录树里快速找到它的完整实现。
【免费下载链接】morphe-patchesMorphe Patches项目地址: https://gitcode.com/gh_mirrors/mo/morphe-patches
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考