news 2026/9/15 14:08:28

Firefox for iOS 构建指南:从环境准备到 User Scripts 与许可证维护的完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Firefox for iOS 构建指南:从环境准备到 User Scripts 与许可证维护的完整实践

Firefox for iOS 构建指南:从环境准备到 User Scripts 与许可证维护的完整实践

【免费下载链接】firefox-iosFirefox for iOS项目地址: https://gitcode.com/GitHub_Trending/fi/firefox-ios

导读

firefox-ios/README.md 是 Mozilla Firefox for iOS 应用的主构建文档,它指导开发者完成从环境准备、依赖安装、Xcode 编译到用户脚本(User Scripts)构建与许可证致谢维护的全流程。本篇文章以该文档为核心骨架,结合仓库中 bootstrap.sh、webpack.config.js、package.json 与license_plist_config.yml等源码与配置,深入讲解每一环节的底层实现与参数细节。读完后,你将掌握 Firefox for iOS 的标准编译流程、User Scripts 的聚合打包机制,以及第三方许可证声明文件的生成方法。

说明:当前仓库是同时包含 Firefox for iOS 与 Focus iOS 两个产品的 monorepo,二者共享工具链;本文聚焦firefox-ios子目录所对应的 Firefox 应用构建链路。

一、构建前环境准备

1.1 工具链与系统要求

根据根目录 README.md 中的徽章信息,当前仓库要求如下:

依赖版本要求
Xcode26.5(以根 README 徽章标注为准)
Swift6.2
最低 iOS 版本iOS 15.0+

在开始之前,请先确认xcode-select -p指向的正是你的 Xcode 安装路径(默认应为/Applications/Xcode.app/Contents/Developer)。由于这是纯 iOS 工程,Xcode 是硬性前置条件。

1.2 Node.js 安装

User Scripts 的构建依赖 Node.js 与 npm,文档推荐通过n(Node 版本管理器)安装并切换到 LTS 版本:

brew install n # 或跳过 brew:curl -L https://bit.ly/n-install | bash n lts

之所以要求 Node.js,是因为仓库根目录的 package.json 声明了 webpack 及其 loader 等构建工具链,并依赖@mozilla/readabilitydarkreaderdompurifypage-metadata-parser等前端库——这些正是后续 User Scripts 打包所要用到的。

二、克隆与一键初始化:bootstrap.sh 干了什么

2.1 克隆仓库

git clone https://github.com/mozilla-mobile/firefox-ios cd firefox-ios

2.2 运行 bootstrap.sh

sh ./bootstrap.sh

这一步是文档给出的核心初始化命令。对照仓库中的 bootstrap.sh 源码,可以发现它并非简单的npm install,而是一个多步骤的引导脚本,按顺序完成:

  1. 安装 SwiftLint:调用 scripts/install-swiftlint.sh 安装仓库固定版本的 SwiftLint(版本由.swiftlint-version文件钉住),用于后续代码规范检查。
  2. 下载 Nimbus FML 引导脚本:从 Mozilla application-services 拉取nimbus-fml.sh,并以./firefox-ios/nimbus.fml.yaml(即 nimbus.fml.yaml)为输入执行,将配置生成到./firefox-ios/bin,用于实验特性(Experiments)的编译期生成。
  3. 安装 Git hooks:将.githooks下的钩子复制到.git/hooks并添加可执行权限,保证后续提交走统一的检查流程。
  4. 安装 npm 依赖并构建用户脚本:依次执行npm installnpm run build,编译出 User Scripts 的 JS 产物(详见下一节)。

脚本默认参数为firefox,也可传focus走 Focus 分支(该分支还会额外克隆shavar-prod-lists并以固定 commit 检出,用于内容拦截列表)。如果你修改了本地化资源想强制重建,可以附加--force参数(该参数会先清理build目录)。

2.3 SPM 依赖问题的兜底方案

文档专门提示:若在 Xcode 中出现 Swift Package Manager(SPM)依赖异常,可执行:

  • Xcode → File → Packages → Reset Package Caches

该操作会清空并重新解析仓库的 SPM 依赖缓存。仓库根目录存在 Package.resolved、BrowserKit/Package.swift、MozillaRustComponents/Package.swift 等多个包清单,任何本地分支切换或版本变更都可能导致依赖缓存与锁文件不一致,重置缓存是官方推荐的恢复手段。

三、在 Xcode 中构建运行

完成初始化后,按以下步骤在 Xcode 中打开并运行:

  1. 打开firefox-ios目录下的Client.xcodeproj(即 firefox-ios/Client.xcodeproj)。
  2. 在 Xcode 中选择Fennecscheme(注意:不是 Firefox,Fennec 是 Mozilla 内部对 Firefox 的代号,工程中的目标命名沿用此惯例)。
  3. 选择目标模拟器或真机设备。
  4. Cmd + R(或点击 Build and Run 按钮)运行。

首次构建时,Xcode 会弹出ModifiedCopySwift 宏的授权确认框,点击Trust & Enable即可继续。这是预期行为——该宏包在 Xcode 26 的构建系统下用于对复制资源进行修改处理;若宏包版本更新,提示会再次出现。

四、深入 User Scripts:注入 WKWebView 的 JavaScript 构建体系

4.1 为什么需要 User Scripts 聚合

Firefox for iOS 通过WKUserScriptWKWebView注入 JavaScript,实现阅读模式、内容拦截统计、密码填充、翻译等能力。但若每个功能都注册一个独立脚本,会显著增加注入数量与性能开销。文档明确给出了解决方案:把脚本按"注入帧(All Frames / Main Frame)× 注入时机(At Document Start / At Document End)"两个维度归并成四类,再用 webpack 分别拼接、压缩。

4.2 目录结构与产物映射

User Scripts 源码位于firefox-ios/Client/Frontend/UserContent/UserScripts目录,其结构与 webpack 的打包入口一一对应:

firefox-ios/Client/Frontend/UserContent/UserScripts |-- AllFrames/ | |-- AtDocumentEnd/ → AllFramesAtDocumentEnd.js | |-- AtDocumentStart/ → AllFramesAtDocumentStart.js |-- MainFrame/ |-- AtDocumentEnd/ → MainFrameAtDocumentEnd.js |-- AtDocumentStart/ → MainFrameAtDocumentStart.js

文档指出:"This reduces the total possible number of User Scripts down to four",即最终只保留四个聚合产物。查看 webpack.config.js 的entry配置可以看到,实际打包入口远不止四个:

  • 基础四类:AllFramesAtDocumentStartAllFramesAtDocumentEndMainFrameAtDocumentStartMainFrameAtDocumentEnd
  • 专项脚本:WebcompatAllFramesAtDocumentStart(站点兼容性)、NightModeAllFramesAtDocumentStart(夜间模式,依赖 Dark Reader)、AutofillAllFramesAtDocumentStart(表单自动填充)、AddressFormManager(地址表单)、TranslationsEngine(翻译引擎)及其运行时动态加载的translations-engine.worker

从仓库目录 UserScripts 中可以看到,AllFrames/AtDocumentStart下包含__firefox__.jsContextMenu.jsDownloadHelper.jsLoginsHelper.jsNoImageModeHelper.jsTrackingProtectionStats.js等;MainFrame/AtDocumentStart下则有ReaderMode.jsReaderModeStyles.jsJSONLD.jsSummarizer.jsTranslationsEntrypoint.jsLanguageSampleExtractor.js等。这些正是打包进各类产物的功能脚本。

webpack 配置中还有一个关键约束:每个"文档开始执行"类别的产物,首个文件必须是__firefox__.js,因为该文件定义了window.__firefox__全局命名空间,后续脚本依赖它进行通信。配置里甚至为此专门写了校验逻辑,如果__firefox__.js不是第一个文件会直接抛错。这也解释了为什么 PDF 内容不会执行 document start 脚本时,需要在 document end 脚本中也引入__firefox__.js

4.3 编译产物与提交策略

聚合压缩后的产物输出到firefox-ios/Client/Assets目录,命名如下:

  • AllFramesAtDocumentEnd.js
  • AllFramesAtDocumentStart.js
  • MainFrameAtDocumentEnd.js
  • MainFrameAtDocumentStart.js

产物输出路径同样在 webpack.config.js 的output中指定为firefox-ios/Client/Assets。文档声明这些编译文件是"checked-in to this repository",即把构建结果提交进仓库,从而让不熟悉前端工具链的贡献者也能直接编译工程。不过需要注意,仓库的 .gitignore(第 101~110 行)目前将这类产物列入了忽略名单,意味着它们会在npm run build时重新生成——也就是说,bootstrap.sh中的npm run build步骤是产物可靠性的保证,切勿跳过。

4.4 开发与生产两种构建模式

文档给出了两种构建命令,均在仓库根目录执行:

命令模式说明
npm run dev开发模式 + watch监听脚本保存并即时重新编译,生成 source map,便于在浏览器/调试器中定位源码行
npm run build生产模式一次性输出压缩后的正式产物,供 App 发布使用

两条命令在 package.json 中对应为webpack --config webpack.config.js --mode development --watchwebpack --config webpack.config.js(默认生产模式)。webpack 配置还处理了桌面端代码中resource://...形式的 URI 导入——通过自定义NormalModuleReplacementPlugin将其替换为Assets/CC_Script/下的本地模块,并依据 Overrides.ios.js 完成 iOS 侧模块覆盖。

五、更新许可证致谢(Settings > Licenses)

Firefox for iOS 在Settings > Licenses界面展示所有使用的开源软件许可证。当引入新的第三方依赖或资源时,必须同步更新致谢列表,官方要求遵循 license_plist_config.yml 的说明操作。

5.1 配置文件与生成命令

该 YAML 文件是 LicensePlist 工具的配置。文档给出的推荐用法是从仓库根目录执行:

license-plist --config-path "./firefox-ios/Client/Assets/About/license_plist_config.yml" \ --package-paths "BrowserKit/Package.swift" \ --xcodeproj-path "firefox-ios/Client.xcodeproj"

关键约定:--package-paths必须包含所有Package.swift文件(新增包文件时应追加到命令中);对于无法被自动扫描到的仓库(例如 Mozilla Rust Components),需要按配置手工补充。

5.2 配置项速览

结合配置文件源码,常用配置含义如下:

  • outputPath: "./LicensePlistTemp":临时输出目录,该目录已被.gitignore忽略,避免无变更时的冗余检查。
  • htmlPath: Licenses.html:生成的最终 HTML 文件名,对应 App 内 Licenses.html 页面。
  • force: true:每次强制重新生成,不依赖缓存。
  • failIfMissingLicense: true:若某个依赖缺少许可证文件则直接失败,从构建层面强制合规。
  • gitHubToken:当 GitHub API 请求被限流时,填入个人访问令牌解除限制。
  • github段:手工罗列无法被自动拾取的远程仓库,如mozilla/readabilitydarkreader/dompurifybignerdranch/Deferred等。
  • manual段:补充非远程仓库,例如使用 Mozilla Public License Version 2.txt 的 Mozilla Rust Components,以及因生成 HTML 文本需要手工修正的 Down、EasyList。
  • rename段:将包名显示为人类可读名称,如firefox-ios → Firefox for iOS
  • exclude段:排除重复条目(如 Down 已在 manual 中手工提供定制 README)。

配置中还有一条 2026 年 2 月的注释提醒:LicensePlist 存在"无法同时在 YAML 中定义xcodeprojPathpackagePaths"的缺陷,因此这两项必须以 CLI 参数形式传入,这也是文档命令必须保留--package-paths--xcodeproj-path的原因。

六、常见问题排查清单

现象处理方式
SPM 依赖解析失败Xcode → File → Packages → Reset Package Caches 后重新构建
User Scripts 修改不生效确认在仓库根目录执行过npm run dev(watch 模式)或npm run build
首次构建弹出宏授权点击 Trust & Enable,属正常流程
LicensePlist 生成报错检查是否补全--package-paths下所有Package.swift;确认新依赖已加入github/manual
GitHub API 限流导致许可证抓取失败在配置中填写gitHubToken

结语

Firefox for iOS 的构建体系围绕"monorepo + webpack 聚合 User Scripts + LicensePlist 合规管理"三条主线展开:bootstrap.sh承担环境初始化,Fennecscheme 是 Xcode 构建入口,User Scripts 的四类产物设计兼顾了注入性能与开发体验,许可证维护则通过配置驱动保证开源合规。理解这套链路后,无论是编译调试、为浏览器注入新脚本,还是补充第三方依赖声明,都能在仓库中找到对应的落点与标准流程。

【免费下载链接】firefox-iosFirefox for iOS项目地址: https://gitcode.com/GitHub_Trending/fi/firefox-ios

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 14:08:15

负载高但CPU空闲?一次定时任务引发的上下文切换过高排查实践

1. 从一次“用户说慢”到实际定位,我走过的弯路先说当时的具体场景。那是一个再普通不过的工作日早上,运营突然在群里反馈:后台管理页面的数据刷新很慢,一个列表接口平时 300ms 左右,现在经常要 2、3 秒,部…

作者头像 李华
网站建设 2026/9/15 14:07:22

大文件上传、断点续传、秒传

#如何系统性地设计一个支持大文件上传和断点续传的方案面试答案核心架构:“三驾马车”一个成熟的方案通常是三大核心技术的组合:分片上传 (Chunked Upload)、断点续传 (Resumable Upload) 和秒传 (Instant Upload)。分片上传:为传输大文件“搭…

作者头像 李华
网站建设 2026/9/15 14:06:17

VeraCrypt加密卷挂载失败:完整四阶段卷头恢复流程

VeraCrypt加密卷挂载失败:完整四阶段卷头恢复流程 【免费下载链接】VeraCrypt Disk encryption with strong security based on TrueCrypt 项目地址: https://gitcode.com/GitHub_Trending/ve/VeraCrypt VeraCrypt加密卷的主卷头(卷前部的元数据区…

作者头像 李华
网站建设 2026/9/15 14:03:38

开题报告格式要求太繁琐?6款工具帮你理顺2026论文开局

开题报告的格式要求往往比内容本身更让人头疼——字体字号、行距页边距、参考文献著录规则、各级标题层级,每所学校甚至每个学院都有自己的细则。不少学生把大量时间耗在调整格式上,反而耽误了选题论证和文献综述的打磨。实际上,格式问题完全…

作者头像 李华
网站建设 2026/9/15 14:02:01

如何复现3Blue1Brown的数学动画:manim视频源码库实战指南

如何复现3Blue1Brown的数学动画:manim视频源码库实战指南 【免费下载链接】videos Code for the manim-generated scenes used in 3blue1brown videos 项目地址: https://gitcode.com/GitHub_Trending/vi/videos 给学生讲"复数乘法的旋转角度"&…

作者头像 李华