Article

Passing Messages Between Safari App Extensions and Injected Scripts

Pass data back and forth between Safari App Extension and injected scripts.

Overview

The injected script and your Safari App Extension live in different sandboxed worlds, each with specific limits on what it can access. You can’t call directly from the native code in your app extension to the injected script running in the browser. However, some sort of communication between the two is almost always desirable. For example, you may have a toolbar or contextual menu item that you want to use to affect web content.

The solution is to pass messages between the injected script and the app extension. The two runtime environments share a common format for message passing, and each provides an interface for sending and receiving messages.

The complete workflow is shown below.

Message passing between the app extension and the injected script

Within the scripting environment, you have access to the window and document objects for the browser content as well as a safari object. The safari object is an instance of the SafariAppExtensionNamespace class. It provides details about your app extension and support for passing messages between your injected script and the app extension.

This table describes your app extension’s key properties:

Property

Description

extension

A proxy for the app extension. Use it to retrieve information about your app extension and pass messages to it.

self

A proxy for your injected script. Use it to install event listeners to respond to messages from your app extension.

Send Messages to the App Extension

Call safari.extension.dispatchMessage:

safari.extension.dispatchMessage("Hello World");

The parameter for dispatchMessage is a string that identifies the message you want to send. You create your own message names and decide what those messages mean for your app extension.

You can optionally send additional user data to accompany the message:

safari.extension.dispatchMessage("InterestingMessage",  { "key": "value" });

The user data must be a JavaScript object made up of keys and values that conform to the W3C standard for safe passing of structured data, such as Boolean objects, numeric values, strings, arrays, and so on.

For example, the following snippet sends an array in a message:

var myArray = ["a", "b", "c"];
safari.extension.dispatchMessage("passArray", { "key": myArray });

When the app extension receives the message, the extension handler’s messageReceived(withName:from:userInfo:)method is called. This method's parameters include the message name, the page that sent the message, and, if part of the message, a user dictionary:

override func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String : AnyObject]!) {
    page.getPropertiesWithCompletionHandler { properties in
        NSLog("The extension received a message (\(messageName)) from a script injected into (\(properties?.url)) with userInfo (\(userInfo))")
    }
}

Send Messages to the Injected Script

When the app extension needs to send a message to an injected script, it calls the dispatchMessageToScript(withName:userInfo:) method on the target page:

override func messageReceived(withName messageName: String, from page: SFSafariPage, userInfo: [String : AnyObject]!) {
    page.dispatchMessageToScript(withName: "simpleMessage", userInfo: nil)
    page.dispatchMessageToScript(withName: "complexMessage", userInfo: ["myKey": "myValue"])
}

The message is packaged as an event whose type is "message". To respond to the message, the injected script must register an event listener for message events using safari.self.addEventListener:

safari.self.addEventListener("message", handleMessage);

The event passed into the event handler is a SafariExtensionMessageEvent object. Its name property identifies the message, and its message property contains the dictionary of user data:

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

See Also

Injecting Scripts and Style Sheets

About Injected Style Sheets and Scripts

Learn how you can affect the appearance or behavior of a webpage by using injected style sheets and scripts.

Injecting a Script into a Webpage

Inject a script that you've written from a Safari App Extension into a webpage.

Injecting CSS Style Sheets into a Webpage

Add to or override styles by injecting CSS style sheets into webpages.

class SFSafariExtensionHandler

A base class that you subclass to handle events in your Safari app extension.

class SFSafariExtensionManager

A class used by your app to find out the current state of a Safari app extension.

class SFSafariExtensionState

The state of a Safari app extension.

class SFSafariPageProperties

Information about a webpage.

protocol SFSafariExtensionHandling

A protocol used to implement event handling in a Safari app extension.