在 Windows 小工具面板中顯示 PWA 小工具

各種作業系統都有小工具儀表板,可讓使用者閱讀內容和執行任務。 這方面的例子包括 Android 主屏幕小部件、macOS 儀表板和今天面板小部件、Apple Touch Bar、Samsung Daily Cards、迷你應用程序小部件和智能手錶應用程序小幫手。

在 Windows 11 上,小工具會顯示在 [小工具面板] 中,您可以從工作列左側開啟:

Windows 11 中的小工具版面

在 Windows 11 中,漸進式Web Apps (PWA) 可以定義小部件、更新它們並處理其中的用戶交互。

需要為 PWA 建置自訂小工具

現有的 PWA 不能像使用 Microsoft Edge 提要欄位那樣,直接放入小工具儀表板。 相反,您需要構建適合小部件主機的自定義小部件體驗,目前是 Windows 11 小部件板。 (未來可能會有其他小工具主機。) Windows 11 Widgets Board 要求使用調適型卡片範本建立小工具,而非 HTML 和 JavaScript,因此小工具的設計必須與應用程式 UI 的其餘部分分開設計。

另請參閱:

若要建立 PWA 驅動的小工具並透過 Microsoft Store 進行傳遞,不需要 C++/C# 程式碼。 當您產生小工具,並可以從公用端點成功安裝並執行小工具後,您可以使用 PWABuilder.com 封裝應用程式,並將應用程式傳送到 Microsoft Store,而不需要任何其他程式碼。 支援小工具的 PWA 必須可從公用端點安裝,因為 PWABuilder 不支援從 localhost封裝應用程式。

另請參閱:

安裝 WinAppSDK 並啟用開發人員模式

若要在本機電腦上啟用開發和測試小工具:

  • 安裝 WinAppSDK 1.2。

  • 在 Windows 11 中啟用開發人員模式:

    1. 開啟 [設定]。

    2. 在 [尋找設定 ] 文字方塊中,輸入 developer,然後按一下 [ 使用開發人員功能]。

    3. 啟用 開發人員模式:

      Windows 11 的開發人員設定

定義小工具

Widget 是使用 PWA 資訊清單成員在 widgets PWA 資訊清單檔案中定義。 此資訊清單成員是可以包含多個小工具定義的陣列。

{
  "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 應用程式資訊清單中的小工具定義具有下列必要和選擇性欄位:

欄位 描述 必要?
name 向使用者顯示的小工具標題。 是
short_name 名稱的替代簡寫版本。 否
description 小工具功能的描述。 是
icons 要用於小工具的圖示陣列。 如果遺失, icons 則會改用資訊清單成員。 大於 1024x1024 的圖示會被忽略。 否
screenshots 顯示小工具外觀的螢幕擷取畫面陣列。 screenshot類似於資訊清單成員。 platform螢幕擷取畫面項目的欄位支援 Windows 和 any 值。 大於 1024x1024 像素的影像會被忽略。 如需 Windows 11 小工具面板的特定螢幕擷取畫面需求,請參閱與小工具選擇器整合中的螢幕擷取畫面影像需求。 是
tag 用來在 PWA Service Worker 中參考小工具的字串。 是
template 用來在作業系統小工具儀表板中顯示小工具的範本。 注意:此屬性目前僅供參考,並未使用。 請參閱 ms_ac_template 下方。 否
ms_ac_template 自訂調適型卡片範本的 URL,用來在作業系統小工具儀表板中顯示小工具。 請參閱下方定義 小工具範本 。 是
data 可以找到要填入範本的資料之 URL。 如果存在,此 URL 必須傳回有效的 JSON。 否
type 小工具資料的 MIME 類型。 否
auth 布林值,指出小工具是否需要驗證。 否
update 更新小工具的頻率,以秒為單位。 Service Worker 中的程式碼必須執行更新;小工具不會自動更新。 請參閱 在執行階段存取小工具實例。 否
multiple 布林值,指出是否允許小工具的多個執行個體。 預設為 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 Widget 定義中的欄位。 此欄位應設定為傳回有效 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 範本中的欄位。 在 Service Worker 程式碼中處理小工具動作時,會使用它。 請參閱 處理小工具動作。

在執行階段存取小工具執行個體

您可以存取小工具,並從 PWA Service Worker 程式碼進行更新。 在執行階段存取小工具在下列情況下很有用:

Service Worker 可以存取 self.widgets 物件和數個小組件事件,這些事件共同構成一個 API,您可以用來在執行階段回應變更並存取小組件。

下列各節提供程式碼範例。 如需 API 的參考資料,請參閱 服務工作者 API 參考資料。

在安裝時轉譯小工具

安裝 PWA 後,應用程式在其資訊清單中定義的小工具會新增至小工具儀表板,但尚未安裝。 只有當使用者選擇從儀表板新增小工具時,才會安裝小工具。

安裝小工具時,不會使用小工具定義的 和 欄位data自動ms_ac_template呈現小工具。

若要轉譯小工具,請在服務工作者中接 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 中的服務背景工作者程式碼變更時,瀏覽器會偵測到該變更,安裝新的服務背景工作者,然後稍後啟用該服務背景工作者。

發生這種情況時,請務必更新可能正在執行的任何小工具實例。 Widget 可能在發出 Service Worker 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});
}

處理小工具動作

如果小工具範本包含動作,使用者可以按一下轉譯小工具中的按鈕來執行這些動作。 如需如何在範本中定義動作的相關資訊,請參閱 定義 Widget 動作。

當使用者執行小工具動作時, widgetclick 會在 PWA Service Worker 中觸發事件。 若要處理使用者動作,請接聽事件:

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;
  }
});

簡潔起見,上述程式碼片段中未顯示實際的應用程式程式碼。 收到 或 next-song 動作時previous-song,可能需要使用 Client.postMessage 將訊息傳送至應用程式,讓應用程式知道它應該開始播放上一首或下一首歌曲。

請注意, action 傳遞給上述事件接聽器的物件屬性 widgetEvent 與小工具範本欄位中 action.verb 定義的字串相符。

如需事件的 widgetclick 詳細資訊,以及您可以從中存取哪些資訊,請參閱下方的 Service Worker 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 小部件允許用戶可視化當前歌曲並播放上一首或下一首歌曲。

  1. 如果尚未完成,請安裝 WinAppSDK 1.2 並在 Windows 11 中啟用開發人員模式。

  2. 移至 PWAmp 並在 Windows 11 上安裝應用程式。

  3. 按 Windows 鍵 + W 開啟 Windows 11 小工具面板。

  4. 按一下 [新增小工具 ] 以開啟 小工具設定 畫面,捲動至 PWAmp 迷你播放器 小工具並新增它。

  5. 關閉 小工具設定 畫面。 PWAmp 迷你播放器現在已顯示在 [小工具面板] 中。

PWAmp 小工具顯示目前歌曲和播放上一首或下一首歌曲的按鈕。

Windows 小工具面板,在 PWAmp 示範應用程式旁邊。「小工具面板」包含 PWAmp 迷你播放器小工具,顯示目前在 PWAmp 應用程式中播放的歌曲

Service Worker API 參考

Service Worker 全域物件 (或 ServiceWorkerGlobalScope) widgets 包含公開下列 Promise 型方法的屬性:

方法 描述 參數 傳回值
getByTag(tag) 依標記取得小工具。 小工具標籤 解析為符合標籤的小 工具物件 的 Promise,或 undefined。
getByInstanceId(id) 依執行個體識別碼取得小工具。 小工具執行個體識別碼 解析為對應小 工具物件的 Promise,或 undefined。
getByHostId(id) 依主機識別碼取得小工具。 主機識別碼 在該主機中找到的小 工具物件 陣列。
matchAll(options) 依據比對選項取得小工具。 WidgetOptions 物件 解析為符合準則的小options工具物件陣列的 Promise。
updateByInstanceId(id, payload) 依執行個體識別碼匯報小工具。 執行個體識別碼和 widgetPayload 物件 解析為 undefined 或 Error的 Promise。
updateByTag(tag, payload) 依標記匯報小工具。 小工具標記和 widgetPayload 物件 解析為 undefined 或 Error的 Promise。

Service Worker 全域物件也會定義下列事件:

  • widgetinstall:當小工具主機安裝小工具時觸發。
  • widgetuninstall:當小工具主機正在解除安裝小工具時觸發。
  • widgetresume:當小工具主機繼續呈現已安裝的小工具時觸發,這可能發生在主機暫停小工具轉譯以保留資源之後。
  • widgetclick:當使用者執行其中一個小工具動作時觸發。

如需這些事件所提供物件的詳細資訊,請參閱下方的 widgetEvent 物件 和 widgetClickEvent 物件。

小工具物件

每個小工具都表示為物件 widget ,其中包含下列內容:

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 資訊清單檔案中找到的小工具原始定義。 此物件的內容符合上面 定義 Widget 中列出的內容。

widgetEvent 物件

此物件會以引數的形式傳遞給類型為 、 widgetuninstall及 widgetresume的 Service Worker 小工具事件widgetinstall的接聽器。

針對 widgetinstall、 widgetuninstall及 widgetresume 事件類型,物件 widgetEvent 具有下列屬性:

屬性 描述 類型
widget 觸發事件的小工具執行個體。 小工具
instanceId 小工具執行個體識別碼。 String
hostId 小工具主機識別碼。 String

widgetClickEvent 物件

此物件會以引數的形式傳遞給類型 Service Worker 小工具事件 widgetclick的接聽程式。 您可以使用 來開啟應用程式的視窗來回應事件clients.openWindow()。widgetclick

物件具有 widgetClickEvent 下列屬性:

屬性 描述 類型
action 觸發事件的動作,如小工具範本欄位中 actions.verb 所定義。 請參閱 定義小工具動作。 String
widget 觸發事件的小工具執行個體。 widgetInstance
hostId 小工具主機識別碼。 String
instanceId 小工具執行個體識別碼。 String