Convert Web Extension to Safari App Extension

You should be able to reuse Content Scripts from your Web-Extensions (but you need to rewrite code to be able to send/receive messages with "background"). Background script will have to be re-written in Swift or Objective-C.

You need to developp:

  • a Mac Host Application (which will be a companion to the Extension) : Swift or Objective-C (this app must have minimum features to pass Apple review - check the Apple guidelines for Mac Apps)
  • the extension : in Swift or Objective-C + HTML/JS (as for other browsers) The code in Swift (or Obj-C) for the extension is the equivalent of the background page you have in Web Extensions. It will control the toolbar button, life-cycle of the extension and can talk with injected scripts.

You have an (small) example on Apple website : https://developer.apple.com/documentation/safariservices/safari_app_extensions?changes=_2&language=objc

You should not use Extension Builder anymore (accessible from Developer menu in Safari) since this is for legacy (pure JS) extensions only. So you need to get in XCode.

Last thing, but not least... Safari App Extensions, compared to Safari legacy extensions, are "a bit" more limited (for instance, you won’t be able to open the toolbar popup programmatically, just as with Chrome web-extensions actually).


Now there is an official support for this converting:

Converting a Web Extension for Safari


May be it too late to share my finding, but nevertheless.

Short answer for the possibility of converting web extension to safari app extension is Yes. It definitely possible, But it's hard to do so.

I had a hard time Figuring out the best possible and minimal way to port web extension to safari app-extension.

Problems with porting Web Extension

  1. Safari App-Extension doesn't offer API for tab/window management. (i.e when a tab or window is added, removed or update, unique Identifier for windows and tab)
  2. Require some learning or prior experience with swift/objective -c to implementation background functionality.
  3. Debugging becomes a pain point during development.

Solution

Writing some amount of swift/objective-c code is inevitable. But writing a bridge code in swift/objective C to facilitate the communication between content-script and background-script makes life easier.

  • Approach 1 using bridging code Architectural Design enter image description here

In the diagram, Content-script remains the same, the background-script is injected by creating a webview. Now Any message received from content-script is forward to the webView background-script. Also setup the browser extension API using evaluvateJavascript

webView.evaluateJavaScript("chrome.runtime.id=function() { return "+ extensionId + " }")
  • Approach 2 : Using Electron powered browser extension

Electron JS uses web technologies like simple HTML, CSS, and JavaScript. It does not require native skills unless you want to do something advanced. It can be designed for a single browser. Its file system belongs to Node.js APIs and works on Linux, Mac OS X, Windows.

By using native node modules enables you to write in C++ and ObjectiveC (or Swift) and expose an API to node.js using v8. This gives you a lot of flexibility and power but requires the most time to develop and still being to reuse you background-script by running in electron context.

Sample Application built using this approach https://github.com/AdguardTeam/AdGuardForSafari

If you want to do Window/Tab Management in safari app extension refer WindowTabManagement

UPDATE

If you are planning to port your legacy extension with zero native code (Objective-c/swift). Please follow this repo https://github.com/avast/topee