safari app extensions: broadcast a message to all tabs from swift background process

708 views Asked by At

In a legacy extension it was possible to iterate over safari.application.activeBrowserWindow.tabs to send a message to all tabs registered with the extension.

Is there any equivalent available with the new safari app extensions?

I've been trough the docs but did not find any hints on how to achieve this very basic thing.

A horrible workaround would be to have all tabs ping the Swift background, but really this is such a basic thing it seems absurd that it is not available or covered by the docs, am I missing something?

I also tried keeping a weak map of all "page" instances as seen by "messageReceived" handler in the hope the SFSafariPage reference would be kept until a tab is closed but they are instead lost almost immediately, suggesting they are more message channels than actual Safari pages.

1

There are 1 answers

2
seclace On

The way should be next: in injected.js you send the message to your app-ext, e.g.

document.addEventListener("DOMContentLoaded", function (event) {
    safari.extension.dispatchMessage('REGISTER_PAGE')
})

And in app-ext handle it with smth like this:

var pages: [SFSafariPage] = []

class SafariExtensionHandler: SFSafariExtensionHandler {

    override func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String : Any]?) {
        switch messageName {
        case "REGISTER_PAGE":
            if !pages.contains(page) {
                pages.append(page)
            }
        default:
            return
        }
    }

}

Well, then you can send the message to all opened pages during runtime by smth like this:

for p in pages {
    p.dispatchMessageToScript(withName: "message name", userInfo: userInfo)
}

It looks hacky but yet workable. Enjoy :)