建置 PWA 驅動小工具

各種作業系統都有小工具儀表板,可讓使用者讀取內容並執行工作。 其中的範例包括 Android 主畫面小工具、macOS 儀表板和今日面板小工具、Apple Touch Bar、Samsung Daily Card、迷你應用程式小工具,以及智慧watch應用程式隨附。

在Windows 11上,小工具會出現在您從工作列左側開啟的 Widget 面板中:

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中啟用開發人員模式:

    1. 啟 [設定]

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

    3. 啟用 開發人員模式

      Windows 11的開發人員設定

定義小工具

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螢幕擷取畫面專案的 欄位支援 Windowsany 值。 大於 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。

在上一節中定義的範本包含兩個變數: songartist ,其包含在系結運算式語法中: ${} 。 小工具定義中 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 小工具可讓使用者將目前歌曲視覺化,並播放上一首或下一首歌曲。

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

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

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

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

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

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

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

服務背景工作角色 API 參考

服務背景工作角色全域物件 (或 ServiceWorkerGlobalScope) 包含公開 widgets 下列 Promise 型方法的屬性:

方法 描述 參數 傳回值
getByTag(tag) 依標籤取得小工具 小工具標籤 Promise,解析為符合 標記 的小工具物件 ,或 undefined
getByInstanceId(id) 依實例識別碼取得小工具 小工具實例識別碼 可解析為對應 小工具物件的承諾,或 undefined
getByHostId(id) 依主機識別碼取得小工具 主機識別碼 在該主機中找到 的小工具物件 陣列。
matchAll(options) 藉由比對選項來取得小工具 widgetOptions 物件 Promise,解析為符合準則 的小工具物件options 組。
updateByInstanceId(id, payload) 依實例識別碼更新小工具 實例識別碼和 widgetPayload 物件 解析為 undefinedError 的承諾。
updateByTag(tag, payload) 依標籤更新小工具 小工具標籤和 widgetPayload 物件 解析為 undefinedError 的承諾。

服務工作者全域物件也會定義下列事件:

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

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

Widget 物件

每個小工具都會以 widget 物件表示,其中包含下列屬性:

widgetOptions 物件

使用 matchAll(options) 取得多個小工具時, widgetOptions 必須要有 物件才能篩選要傳回哪些小工具。 物件 widgetOptions 包含下列屬性,所有屬性都是選擇性的:

  • installable:布林值,指出傳回的小工具是否應可安裝。
  • installed:布林值,指出傳回的小工具是否安裝在小工具主機中。
  • tag:字串,用來依標籤篩選傳回的小工具。
  • instanceId:字串,用來依實例識別碼篩選傳回的小工具。
  • hostId:字串,用來依小工具主機識別碼篩選傳回的小工具。

widgetPayload 物件

建立或更新小工具實例時,服務工作者必須傳送填入小工具所需的範本和資料。 範本和資料稱為 承載。 物件 widgetPayload 包含下列屬性:

  • template:作為字串的範本,用來呈現小工具。 這會是調適型卡片範本的字串化 JSON。
  • data:要與小工具範本搭配使用的資料做為字串。 此資料可以是字串化的 JSON 資料。

widgetInstance 物件

此物件代表小工具主機中小工具的指定實例,並包含下列屬性:

  • id:用來參考實例的內部 GUID 字串。
  • host:已安裝此實例之小工具主機的內部指標。
  • updatedDate:物件,表示上次將資料傳送至 實例的時間。
  • payloadwidgetPayload 物件 ,表示傳送到這個實例的最後一個承載。

widgetDefinition 物件

這個物件代表小工具的原始定義,可在 PWA 資訊清單檔案中找到。 這個物件的屬性符合上面定義 小工具中所列的屬性。

widgetEvent 物件

這個物件會當做引數傳遞給類型 widgetinstall 為 、 widgetuninstallwidgetresume 之服務背景工作角色小工具事件的接聽程式。

widgetinstall針對 、 widgetuninstallwidgetresume 事件種類, widgetEvent 物件具有下列屬性:

屬性 描述 類型
widget 觸發事件的小工具實例。 部件
instanceId 小工具實例識別碼。 String
hostId 小工具主機識別碼。 String

widgetClickEvent 物件

這個物件會當做引數傳遞給 類型 widgetclick 之服務背景工作小工具事件的接聽程式。 您可以使用 clients.openWindow() 開啟應用程式的視窗以 widgetclick 回應事件。

物件 widgetClickEvent 具有下列屬性:

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