Passing message to script in all open tabs?

Hey there,


I'm currently developing a Safari App Extension for macOS that injects a script. One feature I am trying to implement involves my extension detecting when the host app has made a change to a file. When the change is made in the host app, I want my extension to be able to send an "update" message to all of the scripts currently running.


However, I have only been able to determine how to pass a message back to the SFSafariPage that most recently sent a message to the extension, or to the "active" tab. For this feature, I'd need to be able to pass a message back to every page currently open in Safari, as all of them may need to updated. Is this possible?

Replies

From what I've read up I can't find anything that makes this possible.


I'm also looking for a feature that would allow my backend to access all tabs that are open in safari. Functionality similar to the Web Browser Tabs API would be ideal, at least the retrieving all the tabs with some information on them like a page instance (for sending messages) and the current URL.

Whilst there does not seem to be any API to get all the current pages/tabs, my testing suggests you probably can store all the pages which were ever used[1], and broadcast them: far as I can say, sending a message to a page object of an already closed tab does nothing at all (the drawback is that it does not seem to be possible to check whether a page is still alive or not in any other way than by a roundtrip, trying to send a message to it and wait whether your script would answer or not).


Of course, this still leaves a problem with a re-launched extension which would not know of tabs not used since. I haven't yet tried that, so there might be some problem, but perhaps all the scripts of all the tabs might send a message to the extension each, say, second, to let it know of them? The extra load should not be that big unless there are thousands of open tabs — and if that happens, I guess the load would be the last problem the user has 🙂


[1] So far it even seems that although the SF* APIs do create page objects all the time and those are not unique, isEqual: seems to group them properly by the real page; therefore, storing those things in a set should work all right, reducing the number of objects to precisely one per real unique page. Not tested though, just an idea!

We are working on an API to allow extension developers to get all of the open windows in Safari, and all of the open tabs in a Safari window.


We hope this will help with the issues that you are seeing here. In the meantime, a few facts that might help:


- -[SFSafariPage isEqual:] will return YES for the same pages, even if pointer equality won't

- SFSafariPage (and Tab and Window) conform to NSSecureCoding, so they can be stored in NSUserDefaults or persisted elsewhere

Great, thanks! An API to enumerate open windows and tabs in a window would definitely help.


I'm glad the equality test works properly to group SPSafariPages of same tab not by chance, but it is an intention and thus can be relied upon.


Thanks a lot for the info of the archivability (is there such a word?!? 😉) of SFSafariPages; I did not know that, and it indeed would help! Very nice.


Here's a couple of ideas for further improvements which might help, too, if feasible to implement:

  • an SFSafariPage might be able to get the SFSafariTab it is part of (and an SFSafariPage might be able to obtain its SFSafariWindow perhaps);
  • if that works, an SFSafariWindow might be able to determine the frame of the window it represents (for the moment, we use JavaScript to get the frame and it seems to work reliably, but this would be much cleaner);
  • an SFSafariPage might allow the user to distinguish whether it represents a root or an iframe;
  • in the latter case, the user might be able to get the appropriate root SFSafariPage.


It would be also nice if we could reliably communicate with a specific script inside of a tab. For the moment, far as my testing goes, it seems that whichever script of the same tab (i.e., the one injected to the root or to any iframe) is sent a message, all the scripts in the page receive it.


We sort of solved all these problems for the moment using a rather elaborated protocol which assigns IDs to scripts, but it would be really nice to have appropriate APIs at the SFxxx level directly, without ugly and potentially unreliable tricks.


Also, we'd need to use GUIs... oh, this would rather hi-jack the thread; I shall use another one, better suited for that, instead.


Thanks again!

Regarding


“... it does not seem to be possible to check whether a page is still alive or not in any other way than by a roundtrip, trying to send a message to it and wait whether your script would answer or not”


I wonder: it sort of looks like that for pages which do not represent a living page anymore, we get no URLs; contrariwise, far as the page still exists, there's a non-empty URL, even if it was just “/”.


Can we rely on that? Any further experience, insider's word, or even better, a piece of documentation I've missed?


Thanks!

Is the API available?

If not when we (safari app extension developers) have it?