你的第二个 Kotlin 版本的 Firefox 插件--让插件可以弹出来

作者:Kirill Rakhman

译者:承香墨影

本文由 Kirill Rakhman 授权翻译并发布。

这篇文章是《你的第一个 Kotlin 版的 Firefox 插件》的续集。你应该先阅读它,以了解在 Kotlin 中编写的 Firefox 扩展插件的基本要求和设置。

在这篇文章中,我们将使用 Kotlin 重写 Mozilla 教程中的 第二个扩展插件。这个扩展插件包含一个带有弹出式菜单的工具栏按钮,可让你用自定义的图像替换当前选项卡的内容。

关于这个插件的一个有趣的地方是,它不像以前那样需要与 WebExtensions API 进行交互。我们将探索两种可能的方案来做到这一点,一种是全但有点繁琐的方式,一种是减少编码量的动态方式。

你可以通过这个地址,找到 Firefox 的官方教程:

https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Your_second_WebExtension

你还可以通过这个 Github 地址,查看到完整的项目:

https://github.com/cypressious/second-firefox-extension-kotlin

扩展

我们扩展插件的主要是一个工具栏按钮。当点击按钮时,会弹出一个窗口,你可以在其中选择要显示的图片

由于扩展脚本与内容处理直接是隔离运行的,因此在工具栏弹出窗口中运行的脚本无法直接操作选项卡的 DOM 。这就是为什么我们需要在当前 DOM 中,再注入第二个处理脚本,让这两个脚本通过消息进行通信。

设置

根据所有 Firefox 扩展插件的要求,我们需要声明一个manifest.json告诉浏览器我们的扩展功能。

第一个难点

如前所述,我们的扩展将由两个独立的脚本文件组成。但是,这带来了一个小问题,因为 Kotlin JS 编译器会将所有 Kotlin 代码合并到一个 JS 文件中。根据KT-6168的 issue,可以通过配置将允许编译成多个文件。

KT-6168:

https://youtrack.jetbrains.com/issue/KT-6168

为了克服这个限制,我们将创建两个模块,一个包含弹出脚本,另一个包含内容脚本。以下是设置所需的文件build.gradlesetting.gradle文件:

build.gradle:

setting.gradle:

Kotlin 的代码将被放置在popup/src/main/kotlincontent_script/src/main/kotlin中。

弹出框

manifest.json中,我们声明,扩展插件有一个工具栏按钮,点击它将显示一个弹出窗口的布局位于popup/choose_beast.html

即使我们在 Kotlin 文件中只是编写逻辑代码,HTML 也必须引用编译的 JS 输出以及必需的 kotlin.js stdlib。

Kotlin

我们代码的入口 main() 函数是打开弹出窗口时运行的函数。它将立即在当前标签中注入我们需要的内容脚本,然后监听弹出窗口中的点击。

注入一个脚本是异步的,并且返回一个Promise,这个操作在 Kolin 不需要做额外的处理,它是原生支持的。

外部声明-静态方法

为了方便和浏览器交互,我们将使用 browser ,它包含所有和浏览器相关的顶级属性操作的 APi。但是 Kotlin 编译器不能提前知道这些声明,因此我们需要提前写下它们,进行标记,才能正常编译。在这个例子中,Kotlin 提供了 external 修饰符,来对它进行修饰。

编写这些声明的过程基本上就是阅读executeScript 的 API文档 并手动转义成 Kotlin 代码。转义是简洁明了的,我们不必声明我们不使用的属性。例如,参数executeScript有 6 个不同的属性,但是因为我们只需要其中一个名字为 file  的属性,所以我们省略了其他 5 个。

executeScript 的 Api 文档地址:

https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/tabs/executeScript

编译器不能验证这些声明是否真正正确,所以我们用转义它的代码来让编译正确。在一个更好的环境下,我们应该可以简单地将这些声明,作为一个 Gradle 依赖项来进行添加,我正在做这些,这就属于另外的一篇文章的内容了。

其他的 kotlin 代码

接下来,我们实施监听点击,并发送消息给我们之前注入的内容脚本。

我们为整个文档设置一个点击监听器。当一个元素被点击,我们查询活动选项卡(发送消息需要一个选项卡的 ID )。然后handleClick,我们调用它来显示或隐藏当前选项卡的内容,并发送消息来显示或隐藏我们自定义的图像。

请注意,browser.tabs.sendMessage要求 message 参数是一个单纯的 Javascript 对象。Kotlin JS 不支持 Object literals(KT-7935),这就是为什么我们创建一个帮助转换的函数 jsObject()  。我们使用特殊的内置函数js常量字符串转换为 Javascript 对象。然后我们在对象上通过 lambda 表达式来初始化它并返回它。该对象具有特殊的类型,dynamic 声明意味着编译器将不会执行任何类型检查,并允许我们对其进行任意的调用。我们可以使用它来分配任意的属性。

代码依赖于external你可以在Github源码中,找到的更多的声明。

https://github.com/cypressious/second-firefox-extension-kotlin/blob/master/popup/src/main/kotlin/helpers.kt

实现注入的内容脚本

内容脚本直接在选项卡中运行,并侦听弹出消息。这是整个代码:

为了防止脚本运行多次,我们在 window 上设置一个属性 hasRuntrue 作为标记。我们使用内置的函数asDynamic来与window通信,dynamic可以方便我们读取和写入任意的属性。

接下来,我们听取消息,并收到他们要么显示或删除一个自定义的图像。

使用外部声明 - 动态的方式

同样,我们需要调用在外部属性中定义的 API browser 对象。作为编写整个声明的替代方法,我们可以采取一个捷径,简单地声明。

./gradlew runDceKotlinJs — continuous

正如我们已经看到的,这可以让我们对这个对象进行任意的调用,同时我们可以保证编译时的安全。

测试插件

要启动安装了扩展程序的 Firefox 实例,我们运行

./gradlew runDceKotlinJs — continuous

web-ext run

代码的任何改变,都会立即被编译渲染。

调试内容脚本

如果需要的话,我们也可以看看当前浏览器中的代码。要调试内容脚本,请打开开发人员工具,然后单击 调试器。你应该能够看到内容脚本的(Kotlin)代码,甚至设置断点。

调试 Popup 脚本

要调试弹出脚本,请打开about:debugging并单击扩展下面的“调试”。

一个新的开发者工具窗口应该打开,请确保你右上角切换弹出按钮是可见的。

不幸的是,在这里我们只能看到生成的JS代码。这是 Firefox bugtracker 的一个众所周知的问题,希望这个问题很快就会解决。

要调试其他类型的脚本,请查看 https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Debugging。

小结

这篇文章中,我们看到了如何在 Kotlin 中编写复杂的 Firefox 扩展插件。在过程中,我们需要解决几个问题:

  • 要生成多个 JS 输出文件,我们需要制作多个模块。

  • 为了调用外部定义的 API,我们需要手工编写定义或放弃类型安全。

  • 要创建JS对象,我们需要一个神奇的函数来写一些普通的 JS 对象

除了这些,编码的过程是相当愉快的。Kotlin 的语法和语言特性使代码简洁而有趣。

这位外国小哥,迷恋上用 Kotlin 写插件了,并且越陷越深,如果有持续的文章,我会据需跟踪翻译。

利用 Kotlin 做一些有趣的事情,例如一个浏览器插件。今天的文章你喜欢吗?留言告诉我。

本文由 Kirill Rakhman 授权翻译并发布。

原文链接:

https://medium.com/@Cypressious/your-second-firefox-extension-in-kotlin-bafd91d87c41

今天在承香墨影公众号的后台,回复『成长』。我会送你一些我整理的学习资料,包含:Android反编译、算法、设计模式、虚拟机、Linux、Kotlin、Python、爬虫、Web项目源码。

推荐阅读:

听说喜欢留言的人,运气都不会太差

点击『阅读原文』查看更多精彩内容

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值