さまざまなオペレーティング システムには、ユーザーがコンテンツを読んだりタスクを実行したりできるウィジェット ダッシュボードがあります。 この例には、Android ホーム画面ウィジェット、macOS ダッシュボードと今日のパネル ウィジェット、Apple Touch Bar、Samsung Daily Cards、ミニ アプリ ウィジェット、スマート ウォッチ アプリ コンパニオンなどがあります。
Windows 11 では、タスク バーの左側から開くウィジェット ボードにウィジェットが表示されます。
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 に出荷できます。 PWABuilder は localhost からのアプリのパッキングをサポートしていないため、ウィジェットを裏付ける PWA はパブリック エンドポイントからインストールできる必要があります。
関連項目:
WinAppSDK をインストールし、開発者モードを有効にする
ローカル コンピューターでウィジェットの開発とテストを有効にするには:
WinAppSDK 1.2 をインストールします。
Windows 11 で開発者モードを有効にします。
[設定] を開きます。
[ 設定を検索] テキスト ボックスに「
developer」と入力し、[ 開発者機能を使用する] をクリックします。開発者モードを有効にする:
ウィジェットを定義する
ウィジェットは、 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 マニフェスト メンバーが代わりに使用されます。 1024 x 1024 より大きいアイコンは無視されます。 |
不要 |
screenshots |
ウィジェットの外観を示すスクリーンショットの配列。
screenshot マニフェスト メンバーに似ています。 スクリーンショット アイテムの platform フィールドは、 Windows 値と any 値をサポートします。 1024x1024 ピクセルを超える画像は無視されます。 Windows 11 ウィジェット ボードに固有のスクリーンショットの要件については、「ウィジェット ピッカーと統合する」の「スクリーンショット画像の要件」を参照してください。 |
はい |
tag |
PWA サービス ワーカーでウィジェットを参照するために使用される文字列。 | はい |
template |
オペレーティング システム ウィジェット ダッシュボードにウィジェットを表示するために使用するテンプレート。 注: このプロパティは現在、情報提供のみを目的としており、使用されていません。 以下の ms_ac_template を参照してください。 |
不要 |
ms_ac_template |
オペレーティング システム ウィジェット ダッシュボードにウィジェットを表示するために使用するカスタム アダプティブ カード テンプレートの URL。 以下の ウィジェットテンプレートの定義 を参照してください。 | はい |
data |
テンプレートに入力するデータが格納される URL。 この 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 を設定する必要があります。
前のセクションで定義したテンプレートには、song と artist の 2 つの変数が含まれており、これはバインディング式の構文 ${} で囲まれています。 ウィジェット定義の data URL によって返されるデータには、これらの変数の値が含まれている必要があります。
data URL が返す内容の例を次に示します。
{
"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"
}
上記の JSON テンプレートの verb フィールドに注意してください。 サービス ワーカー コードでウィジェット アクションを処理するときに使用されます。 ウィ ジェットアクションの処理を参照してください。
実行時にウィジェット インスタンスにアクセスする
ウィジェットにアクセスし、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});
}
ウィジェット アクションを処理する
ウィジェット テンプレートにアクションが含まれている場合、ユーザーはレンダリングされたウィジェットのボタンをクリックしてそれらのアクションを実行できます。 テンプレートでアクションを定義する方法の詳細については、「 ウィジェット・アクションの定義」を参照してください。
ユーザーがウィジェット アクションを実行すると、PWA サービス ワーカーで widgetclick イベントがトリガーされます。 ユーザー アクションを処理するには、イベントをリッスンします。
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 を使用してアプリにメッセージを送信し、前または次の曲の再生を開始すべきことをアプリに知らせる必要があります。
上記のイベントリスナーに渡されたwidgetEventオブジェクトのactionプロパティは、ウィジェットテンプレートの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)には、次のPromiseベースのメソッドを公開する widgets 属性が含まれています。
| メソッド | 説明 | パラメーター | 戻り値 |
|---|---|---|---|
getByTag(tag) |
タグでウィジェットを取得します。 | ウィジェット タグ | タグ (undefined) に一致するウィジェット オブジェクトに解決される Promise。 |
getByInstanceId(id) |
インスタンス ID を使用してウィジェットを取得します。 | ウィジェット インスタンス ID | 対応する ウィジェット オブジェクト ( undefined) に解決される Promise。 |
getByHostId(id) |
ホスト ID でウィジェットを取得します。 | ホスト ID | そのホストで見つかった ウィジェット オブジェクト の配列。 |
matchAll(options) |
オプションを一致させてウィジェットを取得します。 | widgetOptions オブジェクト |
options条件に一致するウィジェット オブジェクトの配列に解決される Promise。 |
updateByInstanceId(id, payload) |
Updates インスタンス ID でウィジェットを更新します。 | インスタンス ID と widgetPayload オブジェクト |
undefinedまたはErrorに解決される Promise。 |
updateByTag(tag, payload) |
タグでウィジェットをUpdatesします。 | ウィジェット タグと widgetPayload オブジェクト |
undefinedまたはErrorに解決される Promise。 |
サービス ワーカー グローバル オブジェクトは、次のイベントも定義します。
-
widgetinstall: ウィジェット ホストがウィジェットをインストールしているときに発生します。 -
widgetuninstall: ウィジェット ホストがウィジェットをアンインストールするときに発生します。 -
widgetresume: ウィジェット ホストがインストールされているウィジェットのレンダリングを再開すると発生します。これは、ホストがリソースを保持するためにウィジェットのレンダリングを中断した後に発生する可能性があります。 -
widgetclick: ユーザーがウィジェット アクションのいずれかを実行したときに発生します。
これらのイベントによって提供されるオブジェクトの詳細については、以下の widgetEvent オブジェクト および widgetClickEvent オブジェクトを参照してください。
ウィジェット オブジェクト
各ウィジェットは、次のプロパティを含む widget オブジェクトとして表されます。
-
installable: ウィジェットがインストール可能かどうかを示すブール値。 -
definition: widgetDefinition オブジェクト。 -
instances: ウィジェットの各インスタンスの現在の状態を表す widgetInstance オブジェクト の配列。
widgetOptions オブジェクト
matchAll(options) を使用して複数のウィジェットを取得する場合、返すウィジェットをフィルタリングするために widgetOptions オブジェクトが必要です。
widgetOptions オブジェクトには以下のプロパティが含まれていますが、これらはすべて省略可能です。
-
installable: 返されるウィジェットがインストール可能かどうかを示すブール値。 -
installed: 返されたウィジェットがウィジェット ホストにインストールされているかどうかを示すブール値。 -
tag: 返されたウィジェットをタグでフィルター処理するために使用される文字列。 -
instanceId: 返されるウィジェットをインスタンス ID でフィルター処理するために使用される文字列。 -
hostId: 返されるウィジェットをウィジェット ホスト ID でフィルター処理するために使用される文字列。
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 |
ウィジェット インスタンス ID。 | String |
hostId |
ウィジェット ホスト ID。 | String |
widgetClickEvent オブジェクト
このオブジェクトは、型 widgetclick のサービス ワーカー ウィジェット イベントのリスナーに引数として渡されます。
clients.openWindow() を使用すると、widgetclick イベントに応答してアプリのウィンドウを開くことができます。
widgetClickEvent オブジェクトには、次のプロパティがあります。
| プロパティ | 説明 | 型 |
|---|---|---|
action |
ウィジェット テンプレートの actions.verb フィールドで定義されている、イベントをトリガーしたアクション。 ウィ ジェット・アクションの定義を参照してください。 |
String |
widget |
イベントをトリガーしたウィジェット インスタンス。 | widgetInstance |
hostId |
ウィジェット ホスト ID。 | String |
instanceId |
ウィジェット インスタンス ID。 | String |