PWA ドリブン ウィジェットを構築する

さまざまなオペレーティング システムには、ユーザーがコンテンツを読み取り、タスクを実行できるウィジェット ダッシュボードがあります。 これには、Android ホーム画面ウィジェット、macOS ダッシュボード、今日のパネル ウィジェット、Apple Touch Bar、Samsung Daily Cards、ミニ アプリ ウィジェット、スマート watch アプリコンパニオンなどがあります。

Windows 11、ウィジェットがウィジェット ボードに表示され、タスク バーの左側から開きます。

Windows 11のウィジェットボード

Windows 11では、プログレッシブ Web Apps (PWA) はウィジェットを定義し、更新し、それらの中のユーザー操作を処理できます。

PWA のカスタム ウィジェットを作成する必要がある

既存の PWA は、Microsoft Edge サイドバーと同様に、ウィジェット ダッシュボードにそのまま配置することはできません。 代わりに、ウィジェット ホストに適したカスタム ウィジェット エクスペリエンスを構築する必要があります。これは現在、Windows 11 Widgets Board です。 (今後、他のウィジェット ホストが存在する可能性があります)。Windows 11 ウィジェット ボードでは、HTML と JavaScript ではなくアダプティブ カード テンプレートを使用してウィジェットを構築する必要があるため、ウィジェットはアプリの UI の残りの部分とは別に設計する必要があります。

関連項目:

PWA ドリブン ウィジェットを構築し、Microsoft ストア経由で配信するには、C++/C# コードは必要ありません。 ウィジェットを作成し、パブリック エンドポイントからウィジェットを正常にインストールして実行できたら、 PWABuilder.com を使用してアプリをパッケージ化し、追加のコードを必要とせずにアプリを Microsoft ストアに発送できます。 PWABuilder.com は localhost からのアプリのパッキングをサポートしていないため、ウィジェットをバッキングする PWA をパブリック エンドポイントからインストールできる必要があります。

関連項目:

WinAppSDK をインストールし、開発者モードを有効にする

ローカル コンピューターでウィジェットの開発とテストを有効にするには:

  • WinAppSDK 1.2 をインストールします。

  • Windows 11で開発者モードを有効にする:

    1. [設定] を開きます。

    2. [ 設定の検索 ] ボックスに「」と入力 developerし、[ 開発者向け機能を使用する] をクリックします。

    3. 開発者モードを有効にする:

      Windows 11の開発者設定

ウィジェットを定義する

ウィジェットは、マニフェスト メンバーを使用して、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 アプリ マニフェストのウィジェット定義には、次の必須フィールドと省略可能なフィールドがあります。

フィールド 説明 必須
name ユーザーに表示されるウィジェットのタイトル。 はい
short_name 別の短いバージョンの名前。 いいえ
description ウィジェットの動作の説明。 はい
icons ウィジェットに使用するアイコンの配列。 存在しない場合は、 icons 代わりにマニフェスト メンバーが使用されます。 1024x1024 より大きいアイコンは無視されます。 いいえ
screenshots ウィジェットの外観を示すスクリーンショットの配列。 マニフェスト メンバーにscreenshot似ています。 スクリーンショット項目のフィールドではplatform、 と any の値がWindowsサポートされています。 1024 x 1024 ピクセルを超える画像は無視されます。 Windows 11 ウィジェット ボードに固有のスクリーンショット要件については、「ウィジェット ピッカーとの統合」のスクリーンショット画像の要件に関するページを参照してください。 はい
tag PWA サービス ワーカーのウィジェットを参照するために使用される文字列。 はい
template オペレーティング システム ウィジェット ダッシュボードにウィジェットを表示するために使用するテンプレート。 注: このプロパティは現在、情報提供のみを行っており、使用されていません。 以下を参照してください ms_ac_template いいえ
ms_ac_template オペレーティング システム ウィジェット ダッシュボードにウィジェットを表示するために使用するカスタム アダプティブ カード テンプレートの URL。 以下 の「ウィジェット テンプレートを定義する」 を参照してください。 はい
data テンプレートに入力するデータが見つかる URL。 存在する場合、有効な JSON を返すには、この URL が必要です。 いいえ
type ウィジェット データの MIME の種類。 いいえ
auth ウィジェットで認証が必要かどうかを示すブール値。 いいえ
update ウィジェットが更新される頻度 (秒単位)。 サービス ワーカーのコードは、更新を実行する必要があります。ウィジェットは自動的に更新されません。 「実行時にウィジェット インスタンスにアクセスする」を参照してください。 いいえ
multiple ウィジェットの複数のインスタンスを許可するかどうかを示すブール値。 既定値は true です。 いいえ

ウィジェット テンプレートを定義する

ウィジェットを簡単に作成し、さまざまなオペレーティング システム ウィジェット ダッシュボードに適応させるために、テンプレートを使用して表示されます。 次の 2 種類のテンプレートが存在します。

  • フィールドを使用して template 名前によって定義される汎用テンプレート。
  • カスタム テンプレート。カスタム テンプレート フィールドを使用して URL によって定義されます。

当面は、カスタム アダプティブ カード テンプレートのみがサポートされています。 アダプティブ カードは、一般的で一貫した方法で UI コンテンツを交換するために使用できるオープンなカード交換形式です。 アダプティブ カードの概要に関するページを参照してください。

Windows 11でカスタム アダプティブ カード テンプレートを定義するには、Web アプリ マニフェストにあるウィジェット定義のフィールドを使用ms_ac_templateします。 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 に設定する必要があります。

前のセクションで定義したテンプレートには、 と artistという 2 つの変数songが含まれています。これは、バインド式の構文で囲まれています。 ${} ウィジェット定義の 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 がインストールされると、アプリがマニフェストで定義するウィジェットはウィジェット ダッシュボードに追加されますが、まだインストールされていません。 ウィジェットは、ユーザーがダッシュボードからウィジェットを追加することを選択した場合にのみインストールされます。

ウィジェットがインストールされると、ウィジェット定義の フィールドと 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 でサービス ワーカー コードが変更されると、ブラウザーはその変更を検出し、新しいサービス ワーカーをインストールしてから、後でアクティブ化します。

この場合は、既に実行されている可能性があるウィジェット インスタンスを更新することが重要です。 サービス ワーカー 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;
  }
});

簡潔にするために、実際のアプリケーション コードは上記のコード スニペットには表示されません。 または next-song アクションがprevious-song受信されると、Client.postMessage を使用して、前または次の曲の再生を開始する必要があることをアプリに通知するメッセージをアプリに送信する必要があります。

上記のイベント リスナーにwidgetEvent渡されるオブジェクトのプロパティは、ウィジェット テンプレートのフィールドでaction.verb定義されている文字列と一致しますaction

イベントとそのイベントからアクセスできる情報の詳細については 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 ウィジェットには、前または次の曲を再生するための現在の曲とボタンが表示されます。

PWAmp デモ アプリの横にある Windows ウィジェット ボード。ウィジェットボードには、PWAmpアプリで再生されている現在の曲を示すPAMPミニプレーヤーウィジェットが含まれています

Service Worker API リファレンス

サービス ワーカー グローバル オブジェクト (または ServiceWorkerGlobalScope) には、 widgets 次の Promise ベースのメソッドを公開する属性が含まれています。

メソッド 説明 パラメーター 戻り値
getByTag(tag) タグでウィジェットを取得する ウィジェット タグ タグに一致する ウィジェット オブジェクト () undefinedに解決される Promise。
getByInstanceId(id) インスタンス ID でウィジェットを取得する ウィジェット インスタンス ID 対応する ウィジェット オブジェクト () undefinedに解決される Promise。
getByHostId(id) ホスト ID でウィジェットを取得する ホスト ID そのホスト内にある ウィジェット オブジェクト の配列。
matchAll(options) 一致するオプションを使用してウィジェットを取得する widgetOptions オブジェクト 条件に一致する ウィジェット オブジェクト の配列に解決される options Promise。
updateByInstanceId(id, payload) インスタンス ID でウィジェットを更新する インスタンス ID と widgetPayload オブジェクト または Errorundefined解決される Promise。
updateByTag(tag, payload) タグでウィジェットを更新する ウィジェット タグと widgetPayload オブジェクト または Errorundefined解決される Promise。

サービス ワーカー グローバル オブジェクトでは、次のイベントも定義されます。

  • widgetinstall: ウィジェット ホストがウィジェットをインストールしているときに発生します。
  • widgetuninstall: ウィジェット ホストがウィジェットをアンインストールしているときに発生します。
  • widgetresume: ウィジェット ホストがインストールされたウィジェットのレンダリングを再開したときに発生します。これは、ホストがリソースを保持するためにウィジェットのレンダリングを中断した後に発生する可能性があります。
  • widgetclick: ユーザーがウィジェット アクションの 1 つを実行したときに発生します。

これらのイベントで提供されるオブジェクトの詳細については、以下の widgetEvent オブジェクトwidgetClickEvent オブジェクト 定義を参照してください。

widget オブジェクト

各ウィジェットは、次のプロパティを widget 含むオブジェクトとして表されます。

widgetOptions オブジェクト

を使用して matchAll(options) 複数のウィジェットを取得する場合は、 widgetOptions 返すウィジェットをフィルター処理するためにオブジェクトが必要です。 オブジェクトには widgetOptions 次のプロパティが含まれています。これらはすべて省略可能です。

  • installable: 返されたウィジェットをインストール可能にする必要があるかどうかを示すブール値。
  • installed: 返されたウィジェットがウィジェット ホストにインストールされているかどうかを示すブール値。
  • tag: 返されたウィジェットをタグでフィルター処理するために使用される文字列。
  • instanceId: 返されたウィジェットをインスタンス ID でフィルター処理するために使用される文字列。
  • hostId: 返されたウィジェットをウィジェット ホスト ID でフィルター処理するために使用される文字列。

widgetPayload オブジェクト

ウィジェット インスタンスを作成または更新する場合、サービス ワーカーは、ウィジェットを設定するために必要なテンプレートとデータを送信する必要があります。 テンプレートとデータは ペイロードと呼ばれます。 オブジェクトには widgetPayload 、次のプロパティが含まれています。

  • template: ウィジェットのレンダリングに使用するテンプレートを文字列として指定します。 これは、アダプティブ カード テンプレートの文字列化された JSON になります。
  • data: ウィジェット テンプレートで使用するデータを文字列として指定します。 このデータは、JSON データを文字列化できます。

widgetInstance オブジェクト

このオブジェクトは、ウィジェット ホスト内のウィジェットの特定のインスタンスを表し、次のプロパティを含みます。

  • id: インスタンスを参照するために使用される内部 GUID 文字列。
  • host: このインスタンスをインストールしたウィジェット ホストへの内部ポインター。
  • updatedDate: 最後にデータがインスタンスに送信された時刻を表す オブジェクト。
  • payload: このインスタンスに送信された最後のペイロードを表す widgetPayload オブジェクト

widgetDefinition オブジェクト

このオブジェクトは、PWA マニフェスト ファイルにあるウィジェットの元の定義を表します。 このオブジェクトのプロパティは、上記の「 ウィジェットの定義」に記載されているプロパティと一致します。

widgetEvent オブジェクト

このオブジェクトは、、 型widgetinstallwidgetuninstallwidgetresumeのサービス ワーカー ウィジェット イベントのリスナーに引数として渡されます。

widgetinstallwidgetuninstall、および widgetresume イベント型のwidgetEvent場合、オブジェクトには次のプロパティがあります。

プロパティ 説明
widget イベントをトリガーしたウィジェット インスタンス。 ウィジェット
instanceId ウィジェット インスタンス ID。 String
hostId ウィジェット ホスト ID。 String

widgetClickEvent オブジェクト

このオブジェクトは、 型 widgetclickのサービス ワーカー ウィジェット イベントのリスナーに引数として渡されます。 を使用clients.openWindow()して、イベントに応答してアプリのwidgetclickウィンドウを開くことができます。

オブジェクトには widgetClickEvent 、次のプロパティがあります。

プロパティ 説明
action ウィジェット テンプレートのフィールドで定義されているイベントを actions.verb トリガーしたアクション。 ウィジェット アクションの定義に関するページを参照してください。 String
widget イベントをトリガーしたウィジェット インスタンス。 widgetInstance
hostId ウィジェット ホスト ID。 String
instanceId ウィジェット インスタンス ID。 String