This explainer is for the Shortcut API
Some platforms like Windows and Android have ways to add menu items to the app launcher icon itself, here after called shortcuts. These can perform certain app actions. On Android in addition, you can drag these shortcuts to the homescreen.
The shortcut list (aka menu) contains a mixture of static and dynamic shortcuts and has a limit which may be different per platform or per launcher used. The amount of shortcuts on the homescreen is not limited so though the shortcut list may change overtime, existing shortcuts on the homescreen can still be updated (say change icon) though not removed.
The shortcuts are quite useful as /shortcuts/ to common actions, like starting a chat with the person you chat with the most, or say launch the web app to a specific place inside the app (deep link).
These are becoming quite popular, like for instance in GMaps you can add a shortcut to your contributions page.
The ShortcutInfo dictionary is reusing name, short_name and icons from the manifest specification and can itself be embedded in the manifest.json inside the shortcuts
member which takes an array of ShortcutInfo
.
dictionary ShortcutInfo {
DOMString id;
DOMString name;
DOMString short_name;
sequence icons;
dictionary data;
}
partial interface Navigator {
readonly attribute int maxVisibleShortcuts;
sequence<ShortcutInfo> getManifestShortcuts();
sequence<ShortcutInfo> getDynamicShortcuts();
Promise addShortcut(ShortcutInfo);
Promise removeShortcut(ShortcutInfo);
Promise setShortcut(ShortcutInfo);
Promise requestPinShortcut(ShortcutInfo);
};
[Constructor(DOMString type, optional ShortcutEventInit eventInitDict), Exposed=ServiceWorker]
Interface ShortcutEvent : ExtendableEvent {
readonly attribute DOMString id;
readonly attribute any data;
};
{
"name": "Cool Email",
"start_url": "https://coolemail.com",
…
"shortcuts": [{
"name": "Email Mom",
"id": "send-email",
"data": { "email": "[email protected]" },
"icons": [{
"src": "icon/hd_hi.svg",
"sizes": "any"
}]
}]
}
Similarly to the Push API, when shortcuts are clicked, the shortcutclick
event is fired in the Service Worker.
At that point you have access to the id and data of the shortcut and can easily access any existing open window for the PWA or open the app using openWindow
. postMessage
can be used to talk to the open instance.
This is quite flexible. Using a Service Worker, the app can load URLs, execute JavaScript and communicate with a running instance of the PWA, even without giving it focus.
self.addEventListener('shortcutclick', function(event) {
console.log('[Service Worker] Shortcut click Received.');
if (event.id != "send-email) {
return;
}
async function getWindow() {
const client = await clients.matchAll(options).then(function(clientList) {
if (clients.length > 0) {
return clients[0];
}
return clients.openWindow('https://inbox.coolemail.com');
});
client.postMessage({ action: event.id, data: event.data });
await client.focus();
}
event.waitUntil(getWindow());
});
navigator.requestPinShortcut({
name: "Email Mom",
id: "send-email",
data: { email: "[email protected]" },
icons: [{
src: "icon/hd_hi.svg",
sizes: "any"
}]
}).then(info => {
console.log(`Added ${info.title} shortcut`);
})
As it is quite a common case to just load different URLs (deep links into the app), it makes sense to add start_url
to the ShortcutInfo
. Questions is how to handle that. Without Service Worker it could just load the URL direclty.
- Should
shortcutclick
be dispatched when astart_url
is available as the URL might already be part offetch
event if in scope?
https://developer.android.com/guide/topics/ui/shortcuts.html https://developer.android.com/preview/features/pinning-shortcuts-widgets.html https://docs.microsoft.com/en-us/uwp/api/windows.ui.startscreen.jumplist https://github.com/android/platform_frameworks_base/blob/master/core/java/android/content/pm/ShortcutManager.java https://developer.android.com/reference/android/content/pm/ShortcutManager.html https://developer.android.com/reference/android/content/pm/ShortcutInfo.html https://developer.apple.com/ios/3d-touch/ https://developer.apple.com/documentation/uikit/uiapplicationshortcutitem https://electron.atom.io/docs/tutorial/desktop-environment-integration/
Looks cool.
We don't have any other reference to the Web App Manifest in the DOM so it seems odd to have a getManifestIcons. 1) Manifet could mean App Cache Manifest :) 2) I'm not sure would want to methods for getting a list (static and dynamic). Why not have one
getIcons
then it returns an array of objects where one property is the source of the icon (manifest, dynamic, other)? We can do simplelist.filter
then if we want do something interesting.