(iOS) Safari Web Extensions
built with the standard web technologies: HTML, CSS, and JavaScript.
uses the same WebExtension API available for all the major desktop browsers
extensions can be create a new custom Start Page, shown when the user opens a new tab
once enabled, extensions will show up in Safari actions menu
extensions need users permissions (like in the desktop)
Safari Web Extension structure
manifest.jsondescribes the structure of the extension
includes the extension’s name
lists which websites the extension wants to access to
lists what features it supports, such as a pop-up page or a New Tab page
background.jsSafari runs this script in the background when your extension is enabled
allows your extension to listen for various events coming from the browser or other parts of your extension
content.jsthe browser automatically runs this script on web pages that the user visits
this script gives your extension the power to extend and customize pages by directly manipulating them
every extensions has one or more
contentscriptsthe manifest file declares which script runs for which pages
Creating extensions
Safari web extensions are hosted in an app, which can be downloaded as any other app in the App Store
Create a new Safari Web Extension
Create a new Xcode project with the
Safari Extension Apptemplate
Convert an existing Web Extension from another browser
use Xcode’s Safari Web Extension Converter, which generates an Xcode project from that existing extension
xcrun safari-web-extension-converter [options] <path to extension> Add iOS support to a macOS Safari Web Extension
rebuild the project with Xcode’s Safari Web Extension Converter:
xcrun safari-web-extension-converter [options] --rebuild-project <path to extension> Debugging techniques
while our extension is running on an iOS simulator, we can use macOS’s Safari.app Web Inspector by going to
Develop > Simulatorand choose the tab we’re interested in inspectingif you wanted to use macOS’s Safari.app Web Inspector with a physical iOS device, enable Web Inspector support on that device in Safari’s Advanced Settings
view manifest errors in iOS’s Safari’s extension settings
these errors details will only appear in Settings for debug builds of your app from Xcode and not for copies from the App Store or TestFlight
Best practices
non-persistent background page
for
background.jspersistent is only supported for desktop (no iOS/iPadOS)
non-persistent meant that
background.jsis loaded when needed and unloaded when idle for some timeto make a background page non-persistent, add
"persistent": falsein your manifest
"background": { "scripts": [ "background.js" ], "persistent": false }responsive design
use a responsive design that can accommodate various screen sizes
respect viewport safe area to avoid having content placed under Safari’s Tab Bar or the device’s home indicator
use CSS environment variables to calculate the safe area inset to make sure important elements are positioned within the safe area
by using
viewport-fitparameter in your viewport, you can give your web content an edge-to-edge design that still keeps important content within the safe areapop up pages are shown as popovers on iPadOS, as sheets in iOS
test your app with Dynamic Type sizes
pointer events
element.onmousedownworks only on macOSuse
element.onpointerdownfor cross platform support (mouse, touch, or Apple pencil events)
window APIs
windows in iOS are called scenes
each Safari scene is represented with two windows: one for regular browsing and one for Private browsing, meaning on iOS
browser.windows.getAll()gets two objectson iPadOS, if we use two Safari tabs in split view, we will get four windows (and when we create a split view, we will get the
windows.onCreatedevent twice (one for regular and one for Private browsing)windows.create()windows.remove()windows.update()are not supported in iOSwindows.onRemovedis not firedthese restrictions are only for windows, Web Extensions still have full control of tabs creation/deletion etc
feature detection
use feature detection to handle the case an API is not available on iOS:
if (browser.contextMenus) {
browser.contextMenus.create({ title: "Options...", ... });
}
if (browser.webRequest) {
browser.webRequest.onCompleted.addListener(function(details){ ... });
}Privacy considerations
Web Extension permissions
Users opt in to your extension per website
Safari asks for user consent
Permissions is required for any privacy-sensitive API:
Tab URLs and titles
Cookies
Script and stylesheet injection
…
activeTabpermissiongranted when the user invokes your extension
Limited to current website in current tab
Does not require a prompt
add permission to your manifest:
{
"permissions": [ "activeTab" ]
...
}