贡献者指南

目录

GeckoView 贡献者快速入门指南

本指南面向希望为 GeckoView 项目做出贡献的开发者。如果您想开始在您的应用程序中使用 GeckoView,则应参考wiki

背景

GeckoView 是一个公共 API,它将核心 Gecko 功能暴露给 GeckoView 使用者。多个 Mozilla 产品使用 GeckoView 作为它们进入 Gecko 的核心入口点。例如,Android Components 将 GeckoView 作为依赖项,并使用它与 Gecko 通信。Fenix、Focus 和 Reference Browser 将 Android Components 作为依赖项,并在该框架之上构建浏览器。

总体架构如下所示:

Gecko <-> GeckoView <-> Android Components <-> Fenix 或 Focus 或 Reference Browser

  • **Gecko** 是其他组件构建的基础平台。它是一个多层面的强大平台,符合与浏览器机制相关的标准。

  • **GeckoView** 公开 Gecko 的关键部分,供 API 使用者在 Android 系统中使用。通过这种方式公开了一部分关键的 Gecko 功能。它是一个公共 API,因此公共 API 的更改设计为始终不会破坏现有功能,并遵循弃用流程。

  • **Android Components** 链接到 GeckoView 以支持 Gecko 浏览器。它与 Gecko 和 GeckoView 平台无关。例如,可以使用其他浏览器引擎代替 Gecko。它还提供其他可重用的浏览器构建组件。

  • **Fenix 或 Focus 或 Reference Browser** 是最终的应用程序产品。它们包含主要的视图层,并将所有内容连接在一起以形成最终产品。

在解决 Bug 时,请牢记这种架构。识别解决 Bug 的正确层是任何 Bug 的重要第一步。

执行 Bug 修复

第一步,您需要设置 mozilla-centralBootstrap 并构建项目。

一旦您让 GeckoView 构建并运行,您就可以开始贡献了。有一个针对 Git 开发者的 执行 Bug 修复的通用指南 供您参考。要专门为 GeckoView 贡献代码,您需要以下其他信息。

调试代码

由于 GeckoView 位于多个层级上,因此最佳调试工具通常取决于 Bug 所在的层级。对于 Java 或 Kotlin 代码,使用 Android Studio IDE 是连接调试器和设置断点的一种简单方法。在设置原生调试后,它也可以与 C++ 代码一起使用。请参阅有关 原生调试 的本指南。

对于 JavaScript 代码,可以使用 Firefox 桌面版 Nightly 的 about:debugging 部分连接调试器。设备必须设置为支持 USB 连接,并且设备可能需要启用开发者模式。

有时,留下日志以帮助首先跟踪 Bug 究竟位于哪一层更容易,在各个层级上执行此操作:

  • **Java** - Log.i("Any Tag", "Any string " + variable.toString())

    • 可用于在 GeckoView 中进行永久性日志记录,但应遵循现有的日志记录实践。需要导入。

    • 请注意,Android Components 具有不同的永久性日志记录实践。

  • **JavaScript** - dump("Any string " + variable)

    • 可能不用于永久性日志记录。

    • 可能需要使用 JSON.stringify(variable) 在 JavaScript 中反序列化对象。

  • **JavaScript** - debug`Any String ${variable}`

    • 可用于永久性日志记录,但应遵循现有的日志记录实践。需要导入。

    • 建议在早期调试阶段使用 dump

  • **JavaScript** - console.log("Any String " + variable)

    • 可以使用桌面版上的 about:debugging 连接到连接的设备,然后连接到内容进程来查看。

  • **C++** - MOZ_LOG 尚未在 logcat 中正确显示。

    • 添加此行 CreateOrGetModule("modulename")->SetLevel(LogLevel::Verbose); 到代码的此部分 作为查看 MOZ_LOG 日志的临时解决方案。

  • **C++** - printf_stderr("Any String")__android_log_write(ANDROID_LOG_INFO, "Any Tag", "Any string");__android_log_print(ANDROID_LOG_INFO, "Any Tag", "Any string");

    • 这些都不应用于永久性日志记录,仅用于调试。对于永久性日志记录,请使用 MOZ_LOG

    • 变量日志记录需要转换为 C 字符串或其他支持的日志记录字符串。

    • GeckoView C++ 文件的永久性日志记录可以类似于以下方式设置:

      #define GVS_LOG(...) MOZ_LOG(sGVSupportLog, LogLevel::Info, (__VA_ARGS__))
      static mozilla::LazyLogModule sGVSupportLog("Any Tag");
      GVS_LOG("Any string");
      

请确保在请求合并之前删除任何非永久性调试日志。

要在 Android 上查看日志,请连接设备并运行 adb logcat -v color 以获取彩色日志,或者使用 Android Studio 日志框架。

在本地运行测试和 linter

为了确保您的补丁不会破坏 GeckoView 中的现有功能,您可以使用以下命令运行 junit 测试套件:

./mach geckoview-junit

此命令还允许您运行单个测试或测试类,例如:

./mach geckoview-junit org.mozilla.geckoview.test.NavigationDelegateTest
./mach geckoview-junit org.mozilla.geckoview.test.NavigationDelegateTest#loadUnknownHost

要查看其他选项的信息,只需运行 ./mach geckoview-junit --help;对于处理间歇性测试失败特别需要注意的是 --repeat N--run-until-failure,它们都完全按照您的预期执行。如果测试间歇性失败,请参考 调试间歇性测试失败 以获取其他提示。

其他测试(例如 mochitests)可以使用以下命令运行:

./mach test <path-or-dir-to-test>

核心 GeckoView lints 为:

# Will perform general Android specific formatting and linting.
./mach lint -l android-format
# Will determine if GeckoView API changes happened, find more info at API documentation below, if changes occurred.
./mach lint --linter android-api-lint
# Will perform static analysis and report required changes.
./mach lint --warnings --outgoing

对于以下 linter,请在命令中添加 --fix 以使 linter 自动修复问题。请注意,使用 --fix 会进行更改。大多数命令也接受特定的文件或目录以加快 linting 速度。

如果您的补丁创建了 GeckoView JavaScript 模块,则应运行 ESLint:

./mach lint -l eslint mobile/android/modules/geckoview/

如果您的补丁对 C++ 文件进行了更改,则应运行 C++ linter 格式化程序:

./mach clang-format -p <path/to/file.cpp>

如果您的补丁对 Python 文件进行了更改:

./mach lint --linter flake8
./mach lint --linter black

此外,有时 lints 可以自动检测并在某些文件上修复,例如:

# Will attempt to detect the linter and fix any issues.
# Note, using ``--fix`` will make code changes.
./mach lint --fix <path-to-file>

更新变更日志和 API 文档

如果您要提交的补丁更改了 GeckoView 的公共 API,则必须确保 API 文档保持最新。

GeckoView 遵循弃用策略,您可以在此 设计文档 中了解更多信息。要弃用 API,请添加弃用标志,并使用弃用通知的标识符,以便所有具有相同标识符的通知将在同一时间删除(请参见下面的示例)。版本是在我们期望删除附加到注释的已弃用成员的主版本。GeckoView 团队制定了一项弃用策略,要求每个向后不兼容的更改保留旧代码 3 个版本,从而允许下游使用者(如 Fenix)有时间异步迁移到新代码而不会破坏构建。

@Deprecated
@DeprecationSchedule(id = "<interface_or_class_of_method>-<method_name>", version = <Current Nightly + 3>)

由于这是一个公共 API,因此必须更新变更日志。请确保遵循变更日志条目的正确格式。在下一个发布版本的标题下,为对 API 进行的更改添加新条目,以及任何相关文件的链接和 Bug 编号。

格式应如下所示:

- Summary of changes that should mention the method name, along with the respective class /
  interface name, the major version and the index, and the bug ID, along with the
  bugzilla link

[<major_version>.<index>]: {{javadoc_uri}}/<url_path>

目前,只需使用对 API 所做的更改摘要更新变更日志(示例中的第一行)。要确定索引,请取 [<major_version>.<index>] 列表中的下一个索引。如果没有列表,则从 index = 1 开始。

  • 添加方法的示例

- Added [`GeckoRuntimeSettings.Builder#aboutConfigEnabled`][71.12] to control whether or
  not `about:config` should be available.
  ([bug 1540065]({{bugzilla}}1540065))

[71.12]: {{javadoc_uri}}/GeckoRuntimeSettings.Builder.html#aboutConfigEnabled(boolean)
  • 弃用方法的示例

- ⚠️ Deprecated [`GeckoSession.ContentDelegate.onProductUrl`][128.5], will now be removed in v131.
([bug 1898055]({{bugzilla}}1898055))

[128.5]: {{javadoc_uri}}/GeckoSession.ContentDelegate.html#onProductUrl(org.mozilla.geckoview.GeckoSession)

要检查您的补丁是否更改了 API,请运行以下命令:

./mach lint --linter android-api-lint

此命令的输出将通知您您所做的任何更改是否破坏了现有的 API。命令的第一次运行将告诉您是否存在 API 更改。如果存在更改并且预期更改,请查看更改并按照其提供的说明操作。

./mach gradle geckoview:apiLintWithGeckoBinariesDebug

运行上述命令应该会导致构建失败,并且输出应该包含一个 API 密钥,该密钥应该用于更新变更日志中的 [api-version] 字段。接下来,再次运行该命令:

./mach gradle geckoview:apiLintWithGeckoBinariesDebug

这次构建应该通过,并且将为更改生成一个 api.txt 文件。接下来,按照下一个命令再次检查所做的更改是否不会破坏现有的 API:

./mach lint --linter android-api-lint

如果弃用了 API,请提交后续 Bug 或通过添加关键字 leave-open 保持 Bug 打开以删除和清理其将在哪个版本中删除的已弃用 API。此外,请确保运行前两个命令已将已弃用方法的 javadoc 更改为指示该方法已计划弃用。如果不是,请手动执行此操作。

特殊情况是,更改 API 的补丁可能需要提升到 mozilla-central 的早期分支,例如 beta 频道。为此,请按照通常的提升步骤操作,并为提升创建补丁版本,该版本映射到新的目标分支并重新运行 API linter 命令。

接下来,我们将创建本地 JavaDoc:

在本地创建 JavaDoc

注意

确保更改日志中已更新 API 版本,并且更改日志中对 API 所做更改的摘要已正确填写。否则,此步骤将无法正常工作。

GeckoView 是一个公共 API,因此维护良好的 javadoc 是一种重要的实践。要在本地创建 javadoc,我们使用以下命令

./mach gradle geckoview:javadocWithGeckoBinariesDebug

要在本地查看 javadoc,可以选择以下两个选项之一

  • 导航到 <mozilla-central root>/<build architecture>/gradle/build/mobile/android/geckoview/docs/javadoc/withGeckoBinaries-debug

  • 在您的 mozilla-unified 目录中,输入以下命令

    find . -name withGeckoBinaries-debug
    

    这将返回本地 javadoc 的相对路径。

    例如,输出可能是这样

    mozilla-unified/objdir-frontend/gradle/build/mobile/android/geckoview/docs/javadoc/withGeckoBinaries-debug
    

    然后,使用以下命令进入本地 javadoc 的目录

    cd path_of_javadoc_from_above
    

现在,我们想要启动一个本地 Web 服务器。要本地启动,可以使用任何 Web 服务器,例如

python3 -m http.server 8000

在此示例中,通过 https://127.0.0.1:8000/org/mozilla/geckoview/ 导航到 Web 文档。

注意

如果您收到 404 错误,请确保您已导航到正确的目录,然后尝试重新启动 Web 服务器。

然后,在网页上显示的列表中查找已更改的方法,并单击它。

在更改日志中,主要版本摘要列表下方,应该有一个已更改方法的 URL 列表。为下一个索引添加一个新条目(保持主要版本不变)。然后,在本地 Web 服务器中,复制 .../org/mozilla/geckoview/ 后面的所有内容。通过执行 {{javadoc_uri}}/<paste_the_copied_text> 填写条目。请参阅上面的示例以供参考。

提交到 try 服务器

建议在提交补丁之前运行您的测试。您可以使用 Mozilla 的 try 服务器来执行此操作。要将 GeckoView 补丁提交到 try(在提交审查之前),请键入

./mach try --preset android-geckoview

这将自动运行来自 GeckoView 测试套件的关键测试。如果您的补丁在 try 上通过,则可以(相当)确信它在审查后会成功落地。

try 上的失败将以橙色突出显示的测试名称显示。选择测试以了解更多信息。由于测试工具的问题,偶尔会出现间歇性故障。重新触发测试是确认它是间歇性故障而不是由补丁引起的的好方法。通常,对于已记录的间歇性故障,还将有一个错误号以及一部分堆栈跟踪。有关更多信息,请参阅 间歇性测试故障

要调试 try 上的故障,始终建议检查 logcat。为此,选择单个测试,选择“工件和调试”,然后从“logcat-emulator-5554.log”打开日志。

标记审阅者

将补丁提交到 Phabricator 时,如果您知道您希望谁来审查您的补丁,请将其 Phabricator 句柄放在 reviewers 字段中。

如果您不知道在 Phabricator 提交消息中标记谁进行审查,请将该字段留空,并在提交后,按照 Phabricator 中补丁的链接,然后滚动到屏幕底部,直到看到评论框。

  • 选择 Add Action 下拉菜单,然后选择 Change Reviewers 选项。

  • 在显示的框中,添加 geckoview-reviewers。选择此组作为审阅者将通知 GeckoView 团队的所有成员有一个补丁需要审查。

  • 单击 Submit 提交审阅者更改请求。

GeckoView、Android 组件、Fenix、Focus 和参考浏览器依赖项替换

在 mozilla-central 上的完整构建中,内部产品依赖项替换会自动处理。构建时,替换到这些其他产品的操作将在运行 ./mach build 后自动发生。但是,在工件构建中,Gecko 或 GeckoView 中的更改不会始终如一地反映出来。如果要对 Gecko 或 GeckoView 进行更改,则**强烈**建议仅使用完整构建,因为在使用工件构建时,Gecko 或 GeckoView 中的更改可能不会反映出来。

包含 GeckoView 作为依赖项

如果要将 GeckoView 的开发版本作为依赖项包含在另一个应用程序中,则必须链接到本地副本。实现此目标的方法有多种,但首选方法是使用 Gradle 的依赖项替换机制,该机制在 mozilla-central 中具有第一类支持,并且在 Mozilla 的 GeckoView 使用生态系统中具有模式。

好消息是 mach build 生成了您需要的所有内容,因此在进行以下配置后,您应该会发现以下命令会重建您的本地 GeckoView,然后在下游项目中使用您的本地版本。

cd /path/to/mozilla-central && ./mach build
cd /path/to/project && ./gradlew assembleDebug

**请确保您的 ``mozconfig`` 为您的目标设备指定了正确的 ``–target`` 参数。**许多项目使用“ABI 分割”仅将目标设备的本机代码库包含在部署到设备的 APK 中。在 x86-64 和 aarch64 设备上,这可能导致 GeckoView 无法找到任何库,因为有效的 x86 和 ARM 库未包含在已部署的 APK 中。通过将 --target 设置为您的设备支持的确切 ABI 来避免这种情况。

将您的本地 GeckoView 依赖项替换到非 Mozilla 项目中

在尚未对依赖项替换提供一流支持的项目中,您可以自己执行替换。请参阅 substitue-local-geckoview.gradle 中的文档,但大致如下:在每个使用 GeckoView 的 Gradle 项目中,即在每个包含 dependencies { ... 'org.mozilla.geckoview:geckoview-...' } 块的 build.gradle 中,包含以下行

ext.topsrcdir = "/path/to/mozilla-central"
ext.topobjdir = "/path/to/object-directory" // Optional.
apply from: "${topsrcdir}/substitute-local-geckoview.gradle"

当您想返回使用已发布的 GeckoView 构建时,请记住从所有 ``build.gradle`` 文件中删除这些行!

后续步骤