【免费下载链接】reynard-browser
An experimental Gecko-based web browser for iOS 13+.
Reynard Browser 是一款运行在 iOS 13+ 上的Gecko 引擎浏览器,它绕过系统 WebKit,直接复用 Firefox 同款 Gecko 内核。本文带你完整解析它的Gecko 修改体系:366 个补丁文件如何覆盖 Firefox 源码、补丁如何一键应用与再生成,以及 patches/ 目录的组织逻辑。
一、为什么必须给 Gecko 打补丁?
iOS 规定所有 App 必须使用 Apple 的 WebKit 内核,Reynard 的做法是把 Gecko 引擎编译后塞进 App 包,就像 Firefox for iOS 使用 GeckoView 一样。但桌面/Android 的 Gecko 并不了解 iOS 的种种限制:
- JIT 受限:iOS 沙箱默认禁止代码执行(JIT),必须通过私有手段重新开启;
- 没有现成构建链:iOS 版 Gecko 原本依赖 Apple 的 BrowserEngineKit,Reynard 需要自己配置工具链;
- 移动端代码差异:GeckoView 的 JS 端(
sys.mjs)、权限请求、文件选择等都要适配自有 UI。
因此仓库把"改了什么"全部沉淀为patch 文件,而不是直接分叉 Firefox 代码——这样每次升级 Firefox 版本时,只需重新应用一套补丁即可。
二、三大目录 + 三个脚本:补丁管理骨架
整个工程分三块:
| 目录 | 职责 |
|---|---|
| browser/ | Swift 编写的浏览器 App 壳(Xcode 工程) |
| patches/ | 366 个对 Firefox 源码的补丁,按模块目录镜像组织 |
| engine/firefox | Firefox(Gecko)源码子模块 + release.txt 固定版本 |
配合 tools/development/ 下的三个脚本,形成完整闭环:
# 1. 按 release.txt 拉取对应 Firefox 版本 ./tools/development/update-gecko.sh # 2. 把 patches/ 下的补丁全部应用到 engine/firefox ./tools/development/apply-patches.sh # 3.(开发者改完代码后)把相对版本标签的改动重新导出为补丁 ./tools/development/create-patches.sh几个关键细节:
- 版本锚点:engine/release.txt 当前写的是
FIREFOX_157_0_RELEASE。update-gecko.sh 用浅克隆(--depth 1)检出该标签,保证所有人拿到同一份源码; - 严格校验:apply-patches.sh 在打补丁前会检查子模块 HEAD 与标签提交是否一致、工作区是否干净,否则直接拒绝执行,避免"补丁打错版本";
- 3way 应用:补丁通过
git apply --3way应用,遇到冲突会提示你手动解决后继续,而不是整个流程中断; - 一键再生成:create-patches.sh 先用
git diff --name-only <标签>找出所有被改动的文件,再逐文件执行git diff --binary覆盖写回 patches/——所以patches 目录就是子模块相对官方标签的全部改动,升级 Firefox 后跑一遍它就能刷新整套补丁。
三、patches/ 目录结构:完全镜像 Firefox 源码树
补丁文件的路径与 Firefox 仓库内文件一一对应,<文件路径>.patch即命名规则。顶层统计如下:
| 补丁目录 | 数量 | 对应内容 |
|---|---|---|
| patches/gfx/ | 84 | 图形层:WebRender、IOSurface 共享内存、合成器 IPC |
| patches/dom/ | 70 | DOM 事件、地理位置、WebGPU、相机等 |
| patches/widget/ | 55 | UIKit 窗口、输入/触摸/指针、剪贴板、打印 |
| patches/mobile/ | 33 | GeckoView JS 端:sys.mjsactor、权限、阅读模式 |
| patches/js/ | 17 | JIT(Ion、Wasm)可执行内存改造 |
| patches/toolkit/ | 16 | 进程启动、扩展组件、网络 DoH |
| patches/netwerk/ | 14 | HTTP 多进程连接管理、网络链路监控 |
| patches/layout/ | 16 | 排版、可访问光标 |
| patches/xpcom/ | 11 | 线程池、内存压力监控 |
| 其余 10+ 目录 | 余量 | 构建系统、IPC、解码器、三方库等 |
这种"路径镜像"让定位改动变得非常直接——想知道 Firefox 的Ion.cpp被改了什么,就去看 patches/js/src/jit/Ion.cpp.patch。
四、重点补丁深度解析 🔍
4.1 JIT:让 Gecko 在 iOS 沙箱里跑机器码
patches/js/src/jit/ 下的 17 个补丁是整个体系的核心。Firefox 的 JavaScript 引擎(SpiderMonkey)依赖 JIT 生成机器码,iOS 默认禁止这一点,Reynard 的方案是:
- JIT 内存改造:Ion.cpp.patch 引入
WritableJitAllocationFromExecutable等工具(来自新增的ProcessExecutableMemory模块),把"先写后执行"的两段式写入贯穿到代码分配、跳板、重定位表复制的每一处; - Wasm 同步改造:WasmCode.cpp.patch、WasmBuiltins.cpp.patch 让 WebAssembly 编译产物也走同一套可执行内存管理;
- App 侧配合:Swift 端的 JITController.swift 负责在运行时配对设备、启用 JIT,失败则降级到无 JIT 模式;IOSBootstrap.mm.patch 则把 TXM 支持、系统版本等信息通过
SetJITRuntimeInfo上报给引擎侧。
4.2 GPU 进程容错:内容进程如何感知 GPU 进程死亡
多进程浏览器里,内容进程一旦感知不到 GPU 进程的异常就会黑屏。CompositorBridgeChild.cpp.patch 给合成器桥接增加了进程令牌机制:
InitForContent多接收一个aProcessToken参数并缓存;- 当合成器 IPC 以
AbnormalShutdown断开时,内容进程通过ContentChild::SendNotifyGPUProcessLost(mProcessToken)主动上报,上层得以重建 GPU 进程而不是卡死页面。
配套的还有 GPUProcessManager、RemoteCompositorSession 等一系列 patches/gfx/ipc/ 补丁。
4.3 构建系统:为 iOS 打开更多功能开关
mobile/ios/moz.configure.patch 只有寥寥几行,却是"从 Firefox 源码变成 iOS 浏览器引擎"的开关:
+imply_option("--enable-printing", True) +imply_option("--enable-webrtc", True)配合 patches/build/moz.configure/ 的工具链补丁、patches/config/recurse.mk.patch 的构建依赖修复,Gecko 才能在无 BrowserEngineKit 的情况下完成 iOS 交叉编译。
4.4 mobile/ 目录:GeckoView 的 JS 侧适配
patches/mobile/shared/actors/ 里是一批.sys.mjs.patch,例如 LoadURIDelegateChild.sys.mjs.patch、GeckoViewPrompterChild.sys.mjs.patch。GeckoView 的"JS 桥"大量逻辑写在这些 actor 脚本里,Reynard 需要调整 URL 加载委托、权限弹窗、提示框的分发方式,使其与 browser/GeckoView/Prompts/ 下的 Swift 实现对应。阅读模式、下载等 UI 能力同样在这里被重新接线(如 GeckoViewWebExtension.sys.mjs.patch)。
4.5 引擎如何被打进 App 包
编译产物最终由 browser/Scripts/AddGecko.sh 在 Xcode 构建阶段处理:拷贝 dylib 与 XUL 动态库、补齐default-theme主题资源、逐层 codesign,最终打包成GeckoView.framework嵌入 App——这解释了为什么 AltStore 安装时必须勾选"Keep App Extensions"。
五、升级 Firefox 版本的标准工作流
当上游发布新 Firefox 版本时,维护流程非常清晰:
- 修改 engine/release.txt 为新标签(如
FIREFOX_158_0_RELEASE); - 运行
update-gecko.sh检出新版源码; - 运行
apply-patches.sh应用全部 366 个补丁,逐个解决版本漂移导致的冲突; - 若某些补丁已随上游合入或不再需要,直接删除对应文件即可——补丁是"文件级"的,增删都很干净;
- 如需新增本地改动,直接修改
engine/firefox,再用create-patches.sh重新导出整套补丁。
💡 提示:patches/ 目录因含 Firefox 修改,遵循 Mozilla Public License 2.0,而 App 壳代码为 GPLv3(见 LICENSE)。
六、小结
Reynard 的补丁体系可以用三句话概括:
- 不 fork、只打补丁:
patches/完整镜像 Firefox 源码树,366 个补丁即全部改动,版本锚定由 release.txt 管理; - 脚本化闭环:
update-gecko.sh→apply-patches.sh→create-patches.sh覆盖"拉源码、应用、再导出"全流程; - 难点集中在 JIT 与进程模型:可执行内存改造、GPU 进程令牌、iOS 构建开关,正是"让 Firefox 跑在 iPhone 上"的关键三把钥匙。
如果你想在自有 App 中定制 Gecko,这套"目录镜像 + 标签锚定 + 一键再生成"的补丁管理模式非常值得参考。
【免费下载链接】reynard-browser
An experimental Gecko-based web browser for iOS 13+.
相关推荐
Nerd Fonts 中的 Cascadia Code:CaskaydiaCove 打补丁字体与源码级打补丁解析
Nerd Fonts 中的 Cascadia Code:CaskaydiaCove 打补丁字体与源码级打补丁解析 Cascadia Code 是微软为 Wind
开发工具CLINerd Fonts 系列:InconsolataGo——直引号版 Inconsolata 的三种补丁变体与自打补丁实战
Nerd Fonts 系列:InconsolataGo——直引号版 Inconsolata 的三种补丁变体与自打补丁实战 InconsolataGo 是 Ner
开发工具CLIMagisk补丁管理:及时应用安全补丁的方案
Magisk补丁管理:及时应用安全补丁的方案 引言:Android安全补丁的痛点与解决方案 你是否曾遇到过这样的困境:Android系统安全补丁发布后,设备制造
移动开发系统底层
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考