Article

Adjusting Settings for a Toolbar Item

Customize a toolbar item for your Safari App Extension.

Overview

Safari has a user-customizable toolbar that can contain a selection of buttons. A Safari App Extension can provide a new toolbar item, and when the Safari App Extension is enabled, that item is added to the toolbar by default. The user may choose to hide your toolbar item by customizing the toolbar.

A Safari App Extension toolbar item that’s been added to the Safari toolbar.

Your app extension can enable or disable the toolbar item or add badged text to it. When clicked, the toolbar item can either execute a command or display a popover. The decision of which behavior to implement is made at design time. (Popovers are described in more detail in Display a Popover for a Toolbar Item.)

Adding a toolbar item requires three steps:

  1. Creating an image

  2. Filling out the appropriate fields in the Info.plist file

  3. Adding logic that’s triggered when the toolbar button is clicked

To learn how to add a toolbar item, see About Contextual Menu and Toolbar Item Keys.

Localize the Toolbar Label

Provide an InfoPlist.strings file and include localized text for a custom key based on your toolbar identifier. For example, to provide a Polish translation for a toolbar item whose identifier is translate, add the following entry to your strings file:

"Toolbar Button Label for Identifier: translate" = "Przetłumacz";

For more information, see Localizing Property List Values.

Dynamically Change the Image of a Toolbar Item

To update a toolbar item’s image dynamically, Safari uses the setImage(_:) method for SFSafariToolbarItem. Setting the image to nil sets the default image.

Adjust the State of the Toolbar Item

Your app extension has some control over the toolbar item:

  • The app extension can enable or disable the button. Use setEnabled(_:) if your toolbar item is usable only some of the time.

  • The app extension can add a string to the toolbar item as a badge. For example, if your extension contains a list of items that the user can see by clicking the button, you might badge the toolbar item using setBadgeText(_:) with the number of unread items.

State changes can be triggered in either of these ways:

  • Safari can decide, based on the user's actions, that the button's state might need to be changed.

  • Your app extension can force a state change to happen explicitly.

Validate the Safari Toolbar Item

When an event occurs that may require your toolbar’s state to change, Safari calls your app extension’s event handler. The event handler receives parameters that indicate the window the toolbar is displayed in and a completion handler for your app extension to call. Your event handler should determine whether to enable or disable the toolbar button and whether to display a badge, and then should return this information to Safari.

The code below shows one possible implementation of the validateToolbarItem(in:validationHandler:)method. In this case, the app extension has a list of items that it keeps track of, and it adds a badge to the toolbar item with the number of available items.

override func validateToolbarItem(in window: SFSafariWindow, validationHandler: ((Bool, String) -> Void)) {
    // This is called when Safari's state changed in some way that would require the extension's toolbar item to be validated again.
    if items.count == 0
    {
        validationHandler(false,"")
    }
    else
    {
        validationHandler(true,"\(items.count)")
    }
}

Set the Toolbar Information Explicitly

If you have a reference to an SFSafariWindow object, you can use it to get a proxy object for the toolbar item, and then use that object to set the toolbar’s status directly.

override func toolbarItemClicked(in window: SFSafariWindow) {
    window.getToolbarItem { (toolbarItem) in
        toolbarItem?.setEnabled(true, withBadgeText: "1")
    }
}

Add Commands to the Toolbar Item

If you configured your toolbar item to send a command, clicking the toolbar button in Safari causes your extension handler’s toolbarItemClicked(in:) method to be called. You can then process the click however you like. The window was passed in as a parameter, so this code retrieved the toolbar item for that window and updated its badge.

Another common usage when the toolbar item is activated is to forward the message to an injected script on the page, so that the page can be modified in some way. The code below shows one possible way to forward the toolbar action. This code retrieves the active tab on the window that was clicked, uses the tab to retrieve the page, and then dispatches a message to the page.

window.getActiveTab { (activeTab) in
    activeTab?.getActivePage { (activePage) in
        activePage?.dispatchMessageToScript(withName: "DoSomethingInteresting", userInfo: nil)
    }
}

Display a Popover for a Toolbar Item

A popover is a window that pops up over an active window when the toolbar button is pressed—no navigation is required. It can be used to show a small amount of information or complete a small action. The popover closes automatically when the user changes focus (by clicking in another window, for example). The macOS Human Interface Guidelines describe how to best use popovers in Content Views.

In a Safari App Extension, you implement the popover content using native view and view controller objects based on AppKit. When your native application and your Safari App Extension share the same data model, this design also makes it easier to share other pieces of view code between the two. Safari and the operating system do all of the work to display this content within the Safari browser and to process events as they come in.

Your popover is implemented as a subclass of the SFSafariExtensionViewController class; as with other macOS development, typically you'll want to add your own outlets and actions to the view controller, and provide a XIB file for its user interface. The Xcode template for a Safari App Extension provides some boilerplate code to get you started. Use Auto Layout so that your content adapts to different sizes.

If your toolbar item is configured to display a popover, clicking the toolbar button in Safari causes your extension handler’s popoverViewController() method to be called. Your app extension should instantiate and return the popover view controller. In the template, the popover is implemented as a singleton object.

override func popoverViewController() -> SFSafariExtensionViewController {
    return SafariExtensionViewController.shared
}

Before the popover is displayed, your handler’s popoverWillShow(in:) method is called. You can use this method to populate the contents of the window with new information. Similarly, after the popover disappears, the handler’s popoverDidClose(in:) method is called so that you can perform any necessary cleanup.

See Also

Contextual Menu and Toolbar Items

About Contextual Menu and Toolbar Item Keys

Learn about adding contextual menu items and toolbar items to a Safari App Extension with information property list keys.

Adjusting Settings for Contextual Menu Items

Customize contextual menu items for your Safari App Extension.

class SFSafariToolbarItem

A proxy for a Safari app extension toolbar item in a Safari window.

class SFSafariExtensionViewController

The view controller for a popover associated with your app extension.