将Web扩展转换为Safari应用程序扩展。

11
我有一个Web扩展程序,目前可以在Chrome、Firefox和Opera上运行。 现在我想知道是否有一种方法可以使用相同的代码构建Safari应用扩展程序,可能类似于PhoneGap(将所有现有JS代码包装在Safari应用扩展项目中),或者是否存在JavaScript标签处理等限制,某些事情必须编写原生代码来完成。
谢谢。
8个回答

13

您应该能够重用您的Web扩展中的内容脚本(但您需要重写代码以便能够发送/接收与"背景"相关的消息)。

必须使用Swift或Objective-C重新编写后台脚本。

您需要开发:

  • Mac主机应用程序(它将是扩展的伴侣):Swift或Objective-C(此应用程序必须具有最少的功能以通过Apple审核-请查看Mac应用程序的Apple指南)
  • 扩展:使用Swift或Objective-C + HTML / JS(如其他浏览器一样) 扩展中的Swift(或Obj-C)代码相当于您在Web扩展中拥有的背景页面。 它将控制工具栏按钮,扩展的生命周期,并可以与注入的脚本交互。

您可以在Apple网站上找到一个(小)示例:https://developer.apple.com/documentation/safariservices/safari_app_extensions?changes=_2&language=objc

您不应再使用扩展构建器(从Safari的开发者菜单中访问),因为这仅适用于遗留(纯JS)扩展名。所以您需要进入XCode。

最后一件事,但并非最不重要的...与Safari遗留扩展相比,Safari应用程序扩展名有“一点”更受限制(例如,您无法以编程方式打开工具栏弹出窗口,实际上与Chrome网络扩展名一样)。


我已经为Safari应用程序扩展开发人员创建了一个Slack社区,欢迎大家加入我们:https://slofile.com/slack/safariappextdevs - Emmanuel Sellier
1
关于这个问题,我有一些更新。关于应用程序审核,您可以自己分发Mac应用程序并避免某些要求。Safari应用程序扩展仍在开发中,并且正在添加新的API。因此,请关注发布说明。例如,自从撰写本答案以来,现在有一种方法可以通过编程方式打开弹出窗口。但是仍然存在一些问题,它仍然非常受限制,文档和示例严重缺乏。 - quin
Quin 是对的,我们可以通过编程方式打开弹出窗口(如果我没记错的话,自 10.14.2 起)。但是,API 的功能仍然不如 WebExtensions。 - Emmanuel Sellier
1
这也是过时的信息,请不要跟随这个。 - yegorchik
1
过时了...对于 Safari 的最新版本,因为它支持 Web 扩展。 但是,如果您需要支持旧版本或者已经拥有这种扩展(并且不想“回到” Chrome 扩展),它仍然有效。 - Emmanuel Sellier

9

2
好的,我们刚刚为此撰写了一篇博客,以帮助其他人:https://bartsolutions.medium.com/how-to-convert-an-chrome-extension-into-a-safari-web-extension-and-upload-to-mac-app-store-69c0f7142178 - Walty Yeung

7

也许分享我的发现已经太晚了,但是不管怎样。

简短回答关于将Web扩展转换为Safari应用程序扩展的可能性是肯定的。它确实是可能的,但很难做到。

我花了很长时间找出将Web扩展移植到Safari应用程序扩展的最佳可能和最小化的方法。

移植Web扩展的问题

  1. Safari应用程序扩展没有提供选项卡/窗口管理的API。(例如当添加、删除或更新选项卡或窗口时,唯一的标识符)
  2. 需要一些学习或先前使用Swift/Objective-C实现后台功能的经验。
  3. 在开发过程中,调试成为了一个痛点。

解决方案

编写一些Swift/Objective-C代码是不可避免的。但是编写一个桥接代码来促进内容脚本和后台脚本之间的通信会使生活更加轻松。

在这个图示中,内容脚本保持不变,通过创建webview注入背景脚本。现在从内容脚本接收到的任何消息都会转发到webView背景脚本。同时,使用evaluvateJavascript设置浏览器扩展API。

webView.evaluateJavaScript("chrome.runtime.id=function() { return "+ extensionId + " }")
  • 方法2:使用Electron支持的浏览器扩展

Electron JS使用像简单的HTML、CSS和JavaScript这样的Web技术,不需要原生技能,除非您想要做一些高级操作。它可以为单个浏览器设计。其文件系统属于Node.js API,并可在Linux、Mac OS X、Windows上运行。

通过使用本地节点模块,您可以使用C++和ObjectiveC(或Swift)编写代码,并使用v8向node.js公开API。这给了你很大的灵活性和能力,但需要最多的时间来开发,并仍然可以通过在electron上下文中运行来重用你的后台脚本。

使用此方法构建的示例应用程序 https://github.com/AdguardTeam/AdGuardForSafari

如果您想在Safari应用程序扩展中进行窗口/标签管理,请参考WindowTabManagement

更新

如果您计划使用零本地代码(Objective-c/swift)移植您的遗留扩展,请按照此存储库进行操作https://github.com/avast/topee

你能告诉我为什么要散布虚假信息,并且在2020年2月这样做,当你的信息可能已经过时了吗?对于“选项卡/窗口管理” - 它运作得相当好。我只注意到一个小扩展中有一个区别 - Safari不能识别如果你尝试将它们发送到本地URL(safari-web-extension://)上的browser.tabs.sendMessage消息。其他浏览器处理得很好。除此之外,我的应用程序可以从窗口/选项卡中获取大部分数据。ID、标题等都可以获取。它无法获取文档中所述的favIconUrls(兼容性表)。我不知道你为什么会在这上面得到赞。 - yegorchik
这基本上是一篇非常错误和过时的信息,你可以很容易地使用XCode 12+移植WebExtension(甚至只是Chrome插件)。 - yegorchik
对于我的第一个评论,您必须使用browser.runtime.sendMessage,只有在Safari本地URL窗口中才会被捕获。 - yegorchik
@yegorchik 嗯,什么?你在这里说的假信息是什么意思?Safari应用程序扩展与其他浏览器扩展完全不同。背景脚本本身完全是用Native编写的。
  1. Safari应用程序扩展没有任何选项卡管理功能,例如查询选项卡、使用ID获取选项卡[https://developer.apple.com/documentation/safariservices/safari_app_extensions/passing_messages_between_safari_app_extensions_and_injected_scripts](请参阅此处)。
- prasana kannan
Safari仅支持页面,而在其他扩展中,我们可以查询每个选项卡,其中每个选项卡包含多个页面(iframes),并且在Safari应用程序扩展中没有办法检索使用选项卡ID。尽管如此,在Safari后来同意支持“Safari Web Extension”(与“Safari App Extension”不同)的WWDC20事件(2020年6月22日至26日)之后,这些已经过时了。问题特别涉及Safari应用程序扩展,我建议仔细阅读问题。 - prasana kannan

2

您可以很容易地完成这个操作。

  • 请注意,此操作需要使用 Xcode v.12 和 Safari 12 才能正常工作。
  1. 从 Chrome 应用商店下载 .crx 文件。
    1. 我使用了这个网站:https://crxextractor.com
  2. 使用终端解压缩 «unzip» 命令。
  3. 在终端中输入 xcrun safari-web-extension-converter /path/to/manifest/ 并运行它 - 当被询问是否使用 Swift 时,请输入 yes。这将打开 Xcode。
  4. 在 Xcode 中 - 编译并运行。
  5. 现在激活它:
    1. 进入 Safari,然后选择「偏好设置」,启用开发者模式。
    2. 然后转到新的「开发」选项卡 - 在书签旁边。
    3. 选择「允许未经签名的扩展程序」。
  6. 然后转到「偏好设置」和「扩展程序」,您应该会看到您的扩展程序。

0

并不是所有的东西都可以用Swift编写。例如,我尝试从extensionHandler调用dylib,但失败了。


0
如果我们谈论的是Safari应用程序扩展而不是传统的Safari扩展(在Safari v12中已弃用),那么我的理解是需要使用Swift重新编写后台脚本。 关于内容脚本,它们仍然是JS,但所有使用Chrome API调用编写的消息传递必须使用Safari应用程序API进行重写。

0

您可以参考此链接了解如何将Google Chrome扩展程序转换为Firefox或Safari扩展程序。

目前需要进行一些手动操作。

https://github.com/kritollm/chrome-extension-api-for-safari-and-firefox

在我撰写此文章后,我已经注意到另外两个非常相似的项目。

https://code.google.com/p/adblockforchrome/source/browse/trunk/port.js

https://github.com/jetpack-labs/chrome-tailor-jetpack

此外,这里有一个官方指南,介绍如何使用WebExtensions将Chrome扩展转换为Firefox插件。

2
是的,这些工具是用于将Chrome扩展转换为Safari扩展库扩展的。但是苹果宣布Safari扩展库扩展已经被弃用,现在他们只支持Safari应用扩展。链接:https://developer.apple.com/documentation/safariservices/safari_app_extensions?changes=_2https://9to5mac.com/2018/06/09/safari-12-extensions-more/ - Bojan V

0

根据上述内容,内容脚本可以保持与您在Firefox和Chrome扩展中创建的捆绑包相同。您只需要将其包含在您的plist中即可。

为了避免在Swift中重写所有后台逻辑,我使用了一个名为JavascriptCore的由Apple提供的库。这允许您创建一个JavaScript上下文,并从Swift后台将数据传递到JavaScript后台捆绑包。

例如:safariExtensionHandler.swift有一个名为messageReceived的函数。此函数可以使用JavascriptCore从Swift调用代码中的全局JavaScript函数。


你在JavaScriptCore环境中有localStorage和/或IndexedDB吗? 你如何发起AJAX请求?CORS请求是否可行? - DUzun
@DUzun 关于 localStorage: 1- 在我的 Safari 应用程序扩展 JavaScript 包装器中,每次调用将数据存储在 localStorage 中实际上都会调用一个全局函数 global.setInKeychain(data)。 2- global.setInKeychain(_ data:JSValue) 是从 Swift 端实现的,然后注入到我的 Javascript Context 中。我实现了从 Keychain 存储/获取/删除数据。请纠正我如果我错了,对于 CORS,我认为只需在您的 plist 中列出白名单 URL,并将 <img> 标签的 src 属性设置为 baseURI + url 就可以让您在网页上显示图像。 - RawiSader

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接