how to communicate between safari app and html page loaded from safari app extension resources folder

2k views Asked by At

I'm trying to build a simple safari app extension. On about:blank I load a html page from resources folder of extension. Following is the code for that.

//script.js - injected script
if(window.location.href=="about:blank"){
    window.location.href = safari.extension.baseURI + "page.html";
}

I want communication between this loaded page and safari app. Apparently injected script script.js is not available on loaded html page.

I tried linking the script.js to html page inline but the safari object itself is not available for safari.extension.dispatchMessage or safari.self.addEventListener.

EDIT:
with this ( injected script script.js is not available on loaded html page/tab the page is loaded in) I mean that on opening web inspector in resources tab we can't see any extension scripts

4

There are 4 answers

4
Marek B. On

If I understand your question correctly, you need to communicate between the page's javascript and the Safari app extension's native host app. The host app can only be contacted using API safari.extension.dispatchMessage which is accessible only from the injected script.js script but not from the page's JS.

You can solve this by sending and a request event from the page and registering the response event. Your HTML page would contain script:

function sendEventToInjected() {
    var storeEvent = new CustomEvent('myCustomEvent', {"detail": "testData"});
    document.dispatchEvent(storeEvent);

    var responseEventID = 'myResponseEvent';
    document.addEventListener(responseEventID, function respListener(event)
    {
        console.log("Got data from injected script: " + event.detail);
        document.removeEventListener(responseEventID, respListener);
    });
}

Your script.js will catch this event by registering the event listener and can then pass the data over to the extension's native host app. After native host's response is obtained, response event can be dispatched back to the page.

document.addEventListener("myCustomEvent", function(event) {
    console.log("myCustomEvent:" + event.detail);
    safari.extension.dispatchMessage(event.detail);
});

// Listens for messages sent from the app extension's Swift code.
safari.self.addEventListener("message", messageHandler);

function messageHandler(event)
{
    var resp = {detail: "respData"};
    var respEvent = new CustomEvent('myResponseEvent', resp);
    document.dispatchEvent(respEvent);
}
0
Emmanuel Sellier On

You may not "relocate" the page to a safari-extensions:// url but get the HTML code to display from the Safari App Extension (using messaging) and then insert the code in the about:blank page. Result will be the same, except the page url will remain about:blank

0
Vlad On

You can add zero height iframe to your HTML to "force inject" extension script.

<!DOCTYPE html>
<html lang=en>
   <head>
      <title>My Extension!</title>
   </head>
   <body>
      <noscript><strong>We're sorry but App doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript>
      <p>Hi!</p>
      <iframe id="myID" src="https://example.com" height="0" style="border: none;"></iframe>
   </body>
</html>

Here is possible JS:

function handleMessage(event) {
    console.log(event.name);
    console.log(event.message);
}

if (window.top === window) {
   document.addEventListener("DOMContentLoaded", function(event) {
       console.log("[app] Content loaded: main");
       safari.extension.dispatchMessage("Hello from Main!");
       safari.self.addEventListener("message", handleMessage);
   });
} else {
   document.addEventListener("DOMContentLoaded", function(event) {
       console.log("[app] Content loaded: iframe");
       safari.extension.dispatchMessage("Hello from iframe!");
       safari.self.addEventListener("message", handleMessage);
   });
}

Result:

Image 1 Image 2 Image 3

0
dimitrirostavo On

This looks like a bug with Apple. I have filed one with BugReporter.