建置 PWA 驅動小工具
各種作業系統都有小工具儀表板,可讓使用者讀取內容並執行工作。 其中的範例包括 Android 主畫面小工具、macOS 儀表板和今日面板小工具、Apple Touch Bar、Samsung Daily Card、迷你應用程式小工具,以及智慧watch應用程式隨附。
在Windows 11上,小工具會出現在您從工作列左側開啟的 Widget 面板中:
在Windows 11中,漸進式Web Apps (PWA) 可以定義小工具、更新小工具,以及處理它們內的使用者互動。
需要建置 PWA 的自訂小工具
現有的 PWA 無法直接依原樣放入小工具儀表板中,就像您可以使用 Microsoft Edge 提要欄位一樣。 相反地,您必須建置適用于小工具主機的自訂小工具體驗,而小工具主機目前是Windows 11小工具面板。 (未來可能會有其他小工具主機。) Windows 11小工具面板需要使用調適型卡片範本而非 HTML 和 JavaScript 來建置小工具,因此小工具必須與應用程式 UI 的其餘部分分開設計。
另請參閱:
若要建置 PWA 驅動小工具並透過 Microsoft Store 傳遞它,不需要 C++/C# 程式碼。 一旦您已產生小工具,而且可以從公用端點成功安裝和執行小工具,您可以使用 PWABuilder.com 封裝應用程式,並將應用程式寄送至 Microsoft Store,而不需要任何其他程式碼。 支援小工具的 PWA 必須可從公用端點安裝,因為 PWABuilder.com 不支援從 localhost 封裝應用程式。
另請參閱:
安裝 WinAppSDK 並啟用開發人員模式
若要在本機電腦上啟用開發和測試小工具:
安裝 WinAppSDK 1.2。
在Windows 11中啟用開發人員模式:
開 啟 [設定]。
在 [ 尋找設定] 文字方塊中,輸入
developer
,然後按一下 [ 使用開發人員功能]。啟用 開發人員模式:
定義小工具
Widget 是使用資訊清單成員在 PWA 資訊清單檔案中 widgets
定義。 此資訊清單成員是可包含多個小工具定義的陣列。
{
"name": "PWAmp",
"description": "A music player app",
"icons": [
{ "src": "img/icon-96.png", "sizes": "96x96" },
{ "src": "img/icon-128.png", "sizes": "128x128" },
{ "src": "img/icon-256.png", "sizes": "256x256" },
{ "src": "img/icon-512.png", "sizes": "512x512" }
],
"widgets": [
/* widget definitions go here */
]
}
陣列中的 widgets
每個專案都包含數個欄位,如下所示:
{
...
"widgets": [
{
"name": "PWAmp mini player",
"description": "widget to control the PWAmp music player",
"tag": "pwamp",
"template": "pwamp-template",
"ms_ac_template": "widgets/mini-player-template.json",
"data": "widgets/mini-player-data.json",
"type": "application/json",
"screenshots": [
{
"src": "./screenshot-widget.png",
"sizes": "600x400",
"label": "The PWAmp mini-player widget"
}
],
"icons": [
{
"src": "./favicon-16.png",
"sizes": "16x16"
}
],
"auth": false,
"update": 86400
}
]
}
在上述範例中,音樂播放機應用程式會定義迷你播放機小工具。 Web 應用程式資訊清單中的 Widget 定義具有下列必要和選擇性欄位:
欄位 | 描述 | 必要 |
---|---|---|
name |
小工具的標題,呈現給使用者。 | 是 |
short_name |
名稱的替代簡短版本。 | 否 |
description |
小工具用途的描述。 | 是 |
icons |
要用於小工具的圖示陣列。 如果遺漏, icons 則會改用資訊清單成員。 大於 1024x1024 的圖示會被忽略。 |
否 |
screenshots |
顯示小工具外觀的螢幕擷取畫面陣列。 類似于指令 screenshot 清單成員。 platform 螢幕擷取畫面專案的 欄位支援 Windows 和 any 值。 大於 1024x1024 圖元的影像會被忽略。 如需Windows 11小工具面板特定的螢幕擷取畫面需求,請參閱與小工具選擇器整合中的螢幕擷取畫面影像需求。 |
是 |
tag |
用來參考 PWA 服務背景工作角色中小工具的字串。 | 是 |
template |
用來在作業系統小工具儀表板中顯示小工具的範本。 注意:此屬性目前僅供資訊使用且未使用。 請參閱 ms_ac_template 下方。 |
否 |
ms_ac_template |
自訂調適型卡片範本的 URL,用來在作業系統小工具儀表板中顯示小工具。 請參閱下面 的定義小工具範本 。 | 是 |
data |
可找到要填入範本之資料的 URL。 如果存在,則需要此 URL 才能傳回有效的 JSON。 | 否 |
type |
小工具資料的 MIME 類型。 | 否 |
auth |
布林值,指出小工具是否需要驗證。 | 否 |
update |
更新小工具的頻率,以秒為單位。 服務工作者中的程式碼必須執行更新;Widget 不會自動更新。 請參閱 在執行時間存取小工具實例。 | 否 |
multiple |
布林值,指出是否允許 Widget 的多個實例。 預設為 true 。 |
否 |
定義小工具範本
為了讓小工具能夠輕鬆地建立和適應各種作業系統小工具儀表板,它們會使用範本來顯示。 範本有兩種類型:
- 一般範本,由其名稱使用
template
欄位定義。 - 自訂範本,由其 URL 使用自訂範本欄位定義。
目前僅支援自訂調適型卡片範本。 調適型卡片是開放式卡片交換格式,可用來以通用且一致的方式交換 UI 內容。 請參閱 調適型卡片概觀。
若要在 Windows 11 上定義自訂調適型卡片範本,請使用 ms_ac_template
Web 應用程式資訊清單中小工具定義中的 欄位。 雖然 template
目前未使用 ,但它是必要的欄位。
{
...
"template": "pwamp-template",
"ms_ac_template": "widgets/mini-player.json",
...
}
域 ms_ac_template
值應該是範本檔案的有效 URL。
以下是調適型卡片範本的範例:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "Medium",
"text": "Now playing...",
"horizontalAlignment": "Center"
},
{
"type": "TextBlock",
"spacing": "Large",
"weight": "Bolder",
"horizontalAlignment": "Center",
"text": "${song}, by ${artist}",
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5"
}
若要深入瞭解,請參閱 調適型卡片範本化。
接下來,您必須將資料系結至範本。
將資料系結至您的範本
此範本會宣告小工具的使用者介面。 然後,資料會填入此使用者介面。
若要將資料系結至您的範本,請使用 data
小工具定義中的 欄位。 此欄位應設定為會傳回有效 JSON 資料的 URL。
在上一節中定義的範本包含兩個變數: song
和 artist
,其包含在系結運算式語法中: ${}
。 小工具定義中 URL 所 data
傳回的資料應該包含這些變數的值。
以下是 URL 可能傳回的 data
範例:
{
"song": "I Will Always Love You",
"artist": "Whitney Houston"
}
定義小工具動作
如果您想要讓小工具讓使用者執行工作,請定義支援動作的範本。
以下是自訂調適型卡片範本中定義的動作範例:
{
"type": "AdaptiveCard",
"body": [
{
"type": "TextBlock",
"size": "Medium",
"text": "Now playing...",
"horizontalAlignment": "Center"
},
{
"type": "TextBlock",
"spacing": "Large",
"weight": "Bolder",
"horizontalAlignment": "Center",
"text": "${song}, by ${artist}",
}
],
"actions": [
{
"type": "Action.Execute",
"title": "Previous",
"verb": "previous-song"
},
{
"type": "Action.Execute",
"title": "Next",
"verb": "next-song"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.5"
}
verb
請注意上述 JSON 範本中的 欄位。 在您的服務背景工作程式碼中處理小工具動作時,會使用它。 請參閱 處理小工具動作。
在執行時間存取小工具實例
您可以存取小工具,並從 PWA 服務背景工作程式碼加以更新。 在執行時間存取小工具在下列情況中很有用:
服務工作者可以存 self.widgets
取 物件和數個小工具事件,這些事件一起構成 API,可讓您在執行時間回應變更和存取小工具。
下列各節提供程式碼範例。 如需 API 的參考,請參閱 服務背景工作角色 API 參考。
在安裝時轉譯小工具
安裝 PWA 時,應用程式在其資訊清單中定義的小工具會新增至小工具儀表板,但尚未安裝。 只有當使用者選擇從儀表板新增小工具時,才會安裝小工具。
安裝小工具時,不會使用 ms_ac_template
小工具定義的 和 data
欄位自動轉譯。
若要轉譯小工具,請接 widgetinstall
聽服務背景工作角色中的事件,並使用 widgets.updateByTag
函式更新小工具:
// Listen to the widgetinstall event.
self.addEventListener("widgetinstall", event => {
// The widget just got installed, render it using renderWidget.
// Pass the event.widget object to the function.
event.waitUntil(renderWidget(event.widget));
});
async function renderWidget(widget) {
// Get the template and data URLs from the widget definition.
const templateUrl = widget.definition.msAcTemplate;
const dataUrl = widget.definition.data;
// Fetch the template text and data.
const template = await (await fetch(templateUrl)).text();
const data = await (await fetch(dataUrl)).text();
// Render the widget with the template and data.
await self.widgets.updateByTag(widget.definition.tag, {template, data});
}
更新服務背景工作角色更新的小工具
當 PWA 中的服務背景工作程式碼變更時,瀏覽器會偵測到該變更、安裝新的服務背景工作角色,然後稍後再啟動它。
發生這種情況時,請務必更新可能已在執行中的任何小工具實例。 在發出服務背景 activate
工作角色事件之前,可能已安裝小工具。 若要避免顯示空的小工具,請在事件發生時更新您的小工具 activate
// Update the widgets to their initial states
// when the service worker is activated.
self.addEventListener("activate", event => {
event.waitUntil(updateWidgets());
});
async function updateWidgets() {
// Get the widget that match the tag defined in the web app manifest.
const widget = await self.widgets.getByTag("pwamp");
if (!widget) {
return;
}
// Using the widget definition, get the template and data.
const template = await (await fetch(widget.definition.msAcTemplate)).text();
const data = await (await fetch(widget.definition.data)).text();
// Render the widget with the template and data.
await self.widgets.updateByTag(widget.definition.tag, {template, data});
}
處理小工具動作
如果小工具範本包含動作,使用者可以按一下轉譯小工具中的按鈕來執行這些動作。 如需如何在範本中定義動作的資訊,請參閱 定義小工具動作。
當使用者執行小工具動作時, widgetclick
會在 PWA 服務背景工作角色中觸發事件。 若要處理使用者動作,請接聽 事件:
self.addEventListener('widgetclick', (event) => {
switch (event.action) {
case 'previous-song':
// Application logic to play the previous song...
break;
case 'next-song':
// Application logic to play the next song...
break;
}
});
為了簡潔起見,上述程式碼片段不會顯示實際的應用程式程式碼。 previous-song
收到 或 next-song
動作時,可能需要使用Client.postMessage將訊息傳送至應用程式,讓應用程式知道它應該開始播放上一首或下一首歌曲。
請注意, action
傳遞至上述事件接聽程式之物件的 widgetEvent
屬性符合小工具範本欄位中 action.verb
定義的字串。
如需事件的 widgetclick
詳細資訊,以及您可以從中存取哪些資訊,請參閱下方 的服務背景工作角色 API 參考 。
更新應用程式變更的小工具
在上一節中,您已瞭解如何在發生特定小工具事件、小工具動作和服務背景工作更新時更新小工具。 當應用程式中發生某事或推播通知發生時,或是定期更新小工具也很有用。
在本節中,您將瞭解如何使用定期背景同步 API 定期更新小工具。 如需定期背景同步 API 的詳細資訊,請參閱 使用定期背景同步 API 定期取得最新內容。
在下列程式碼片段中,會使用事件接聽程式來回應應用程式小工具的各種生命週期事件。 偵測到小工具安裝時,會註冊定期同步處理,而偵測到移除小工具時,會取消註冊定期同步處理。
發生定期同步事件時,會使用 widgets.updateByTag
函式更新小工具實例。
self.addEventListener("widgetinstall", event => {
event.waitUntil(onWidgetInstall(event.widget));
});
self.addEventListener("widgetuninstall", event => {
event.waitUntil(onWidgetUninstall(event.widget));
});
async function onWidgetInstall(widget) {
// Register a periodic sync, if this wasn't done already.
// We use the same tag for the sync registration and the widget to
// avoid registering several periodic syncs for the same widget.
const tags = await self.registration.periodicSync.getTags();
if (!tags.includes(widget.definition.tag)) {
await self.registration.periodicSync.register(widget.definition.tag, {
minInterval: widget.definition.update
});
}
// And also update the instance.
await updateWidget(widget);
}
async function onWidgetUninstall(widget) {
// On uninstall, unregister the periodic sync.
// If this was the last widget instance, then unregister the periodic sync.
if (widget.instances.length === 1 && "update" in widget.definition) {
await self.registration.periodicSync.unregister(widget.definition.tag);
}
}
// Listen to periodicsync events to update all widget instances
// periodically.
self.addEventListener("periodicsync", async event => {
const widget = await self.widgets.getByTag(event.tag);
if (widget && "update" in widget.definition) {
event.waitUntil(updateWidget(widget));
}
});
async function updateWidget(widget) {
// Get the template and data URLs from the widget definition.
const templateUrl = widget.definition.msAcTemplate;
const dataUrl = widget.definition.data;
// Fetch the template text and data.
const template = await (await fetch(templateUrl)).text();
const data = await (await fetch(dataUrl)).text();
// Render the widget with the template and data.
await self.widgets.updateByTag(widget.definition.tag, {template, data});
}
示範應用程式
PWAmp 是音樂播放程式 PWA 示範應用程式,可定義小工具。 PWAmp 小工具可讓使用者將目前歌曲視覺化,並播放上一首或下一首歌曲。
如果尚未完成,請安裝WinAppSDK 1.2,並在Windows 11中啟用開發人員模式。
移至PWAmp,並在 Windows 11 上安裝應用程式。
按Windows 標誌鍵 + W開啟Windows 11小工具面板。
按一下 [新增小工具 ] 以開啟 小工具設定 畫面,捲動至 PWAmp 迷你播放 器小工具並加以新增。
關閉 小工具設定 畫面。 PWAmp 迷你播放器現在會顯示在小工具面板中。
PWAmp 小工具會顯示目前要播放上一首或下一首歌曲的歌曲和按鈕。
服務背景工作角色 API 參考
服務背景工作角色全域物件 (或 ServiceWorkerGlobalScope) 包含公開 widgets
下列 Promise 型方法的屬性:
方法 | 描述 | 參數 | 傳回值 |
---|---|---|---|
getByTag(tag) |
依標籤取得小工具 | 小工具標籤 | Promise,解析為符合 標記 的小工具物件 ,或 undefined 。 |
getByInstanceId(id) |
依實例識別碼取得小工具 | 小工具實例識別碼 | 可解析為對應 小工具物件的承諾,或 undefined 。 |
getByHostId(id) |
依主機識別碼取得小工具 | 主機識別碼 | 在該主機中找到 的小工具物件 陣列。 |
matchAll(options) |
藉由比對選項來取得小工具 | widgetOptions 物件 | Promise,解析為符合準則 的小工具物件 數 options 組。 |
updateByInstanceId(id, payload) |
依實例識別碼更新小工具 | 實例識別碼和 widgetPayload 物件 | 解析為 undefined 或 Error 的承諾。 |
updateByTag(tag, payload) |
依標籤更新小工具 | 小工具標籤和 widgetPayload 物件 | 解析為 undefined 或 Error 的承諾。 |
服務工作者全域物件也會定義下列事件:
widgetinstall
:當小工具主機正在安裝小工具時引發。widgetuninstall
:當小工具主機卸載小工具時引發。widgetresume
:當小工具主機繼續轉譯已安裝的小工具時引發,這可能會在主機暫停轉譯小工具以保留資源之後發生。widgetclick
:當使用者執行其中一個小工具動作時引發。
如需這些事件所提供之物件的詳細資訊,請參閱下方 的 widgetEvent 物件 和 widgetClickEvent 物件 定義。
Widget 物件
每個小工具都會以 widget
物件表示,其中包含下列屬性:
installable
:布林值,指出小工具是否可安裝。definition
: widgetDefinition 物件。instances
: widgetInstance 物件的陣列 ,代表小工具每個實例的目前狀態。
widgetOptions 物件
使用 matchAll(options)
取得多個小工具時, widgetOptions
必須要有 物件才能篩選要傳回哪些小工具。 物件 widgetOptions
包含下列屬性,所有屬性都是選擇性的:
installable
:布林值,指出傳回的小工具是否應可安裝。installed
:布林值,指出傳回的小工具是否安裝在小工具主機中。tag
:字串,用來依標籤篩選傳回的小工具。instanceId
:字串,用來依實例識別碼篩選傳回的小工具。hostId
:字串,用來依小工具主機識別碼篩選傳回的小工具。
widgetPayload 物件
建立或更新小工具實例時,服務工作者必須傳送填入小工具所需的範本和資料。 範本和資料稱為 承載。 物件 widgetPayload
包含下列屬性:
template
:作為字串的範本,用來呈現小工具。 這會是調適型卡片範本的字串化 JSON。data
:要與小工具範本搭配使用的資料做為字串。 此資料可以是字串化的 JSON 資料。
widgetInstance 物件
此物件代表小工具主機中小工具的指定實例,並包含下列屬性:
id
:用來參考實例的內部 GUID 字串。host
:已安裝此實例之小工具主機的內部指標。updated
Date
:物件,表示上次將資料傳送至 實例的時間。payload
: widgetPayload 物件 ,表示傳送到這個實例的最後一個承載。
widgetDefinition 物件
這個物件代表小工具的原始定義,可在 PWA 資訊清單檔案中找到。 這個物件的屬性符合上面定義 小工具中所列的屬性。
widgetEvent 物件
這個物件會當做引數傳遞給類型 widgetinstall
為 、 widgetuninstall
和 widgetresume
之服務背景工作角色小工具事件的接聽程式。
widgetinstall
針對 、 widgetuninstall
和 widgetresume
事件種類, widgetEvent
物件具有下列屬性:
屬性 | 描述 | 類型 |
---|---|---|
widget |
觸發事件的小工具實例。 | 部件 |
instanceId |
小工具實例識別碼。 | String |
hostId |
小工具主機識別碼。 | String |
widgetClickEvent 物件
這個物件會當做引數傳遞給 類型 widgetclick
之服務背景工作小工具事件的接聽程式。 您可以使用 clients.openWindow()
開啟應用程式的視窗以 widgetclick
回應事件。
物件 widgetClickEvent
具有下列屬性:
屬性 | 描述 | 類型 |
---|---|---|
action |
觸發事件的動作,如小工具範本欄位中 actions.verb 所定義。 請參閱 定義小工具動作。 |
String |
widget |
觸發事件的小工具實例。 | widgetInstance |
hostId |
小工具主機識別碼。 | String |
instanceId |
小工具實例識別碼。 | String |