Win11のウィジェット、作ってる人いなくない？

#  はじめに
経緯はタイトルの通りです。
しばらく前にwindows11のウィジェット機能を一般人が開発できるようになったのに、誰も作ってなくないですか！？
ということで、参考資料の少ない中でなんとか最低限ウィジェット部分に表示させることができたので、ここに具体的なファイルを備忘録します。
### 注意点
* あくまでもウィジェットとして認識させることができたというだけで、具体的な開発はまだ行っておりません
* また、私はPWAに関する知識もほとんどないため、間違いが多分に含まれることが想定されます。その点にはご留意ください
* 本文やファイル内に「PWAmp」や「mini-player」といった文字列が登場するかもしれませんが、これは公式のデモアプリを学習したChatGPTが出した文字列なので、別の文字にしても問題ないと思います。私が改変したせいでファイル間の整合性がなくなってしまうほうが問題だと考えたため、一部そのまま記載しています
# そもそもウィジェットって？？
windows11で「win + W」を押したときに左からﾆｮｷっと出てくるやつです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778018/41ba8ddf-6dc4-4657-8470-3e9fb5808437.png)
実はここに自作のウィジェットを配置することができてしまいます！

# 方法は大きく2通り
・PWA(Webアプリをデスクトップアプリのように使うあれ)
・Win32アプリ

今回はPWAによる駆動方法を使いました。
win32アプリの知識が身についたらそちらでもやってみます。
# 実装
## 動作環境

* WinAppSDK 1.2 ([ここからダウンロード](https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/older-downloads#windows-app-sdk-12))
* windows11 開発者モード (windowsの設定から有効化する)
* Microsoft Edge 最近のバージョン(PWA機能に対応してればOK?)

## 必要なファイル群
```
/project-root
├── index.html
├── manifest.json
├── service-worker.js
├── /widgets
│   ├── [任意のファイル名-レイアウト].json
│   └── [任意のファイル名-データ].json
├── /img
│   └── icon-128.png
├── favicon-16.png
└── screenshot-widget.png
```
## 各ファイルの役割
### index.html
PWAをダウンロードする際にアクセスするページ。最低限で構わない。
### manifest.json
PWAをダウンロードする際に参照されるファイル。これがないとPWAとして認識されない？？
### service-worker.js
PWAの中で動作するJavaScript。ここでキャッシュの作成などを行うらしい。後述するが、ウィジェットの動作にも関わる。
### favicon-16.png
アイコンになるもの。必要かはわからない。
### screenshot-widget.png
ウィジェット選択画面でプレビューされるもの？？
### ./widgets/[任意のファイル名-レイアウト].json
実際のウィジェットの画面をこのjsonで設計する。意外と自由度は高く、htmlみたいな感じで設計できる。
### ./widgets/[任意のファイル名-データ].json
ウィジェットに表示する情報はこちらに書き込み、それをレイアウト担当側で読み込む。

## 具体的なファイルの中身
### index.html
```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>PWAmp</title>

    <!-- リンク: マニフェスト -->
    <link rel="manifest" href="manifest.json" />

    <!-- アイコン -->
    <link rel="icon" href="favicon-16.png" sizes="16x16" />

    <!-- PWA 用のテーマカラー -->
    <meta name="theme-color" content="#000000" />

</head>

<body>
    <h1>Welcome to PWA</h1>
    <script>
        if ('serviceWorker' in navigator) {
            navigator.serviceWorker.register('service-worker.js')
                .then(() => console.log('Service Worker registered'))
                .catch(err => console.error('Service Worker registration failed:', err));
        }
    </script>
</body>

</html>
```
### manifest.json
```json
{
    "name": "PWA",
    "description": "hogehoge",
    "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": [
        {
            "name": "name",
            "description": "hogehoge",
            "tag": "pwamp",
            "template": "pwamp-template",
            "ms_ac_template": "widgets/[任意のファイル名-レイアウト].json",
            "data": "widgets/[任意のファイル名-データ].json",
            "type": "application/json",
            "screenshots": [
                {
                    "src": "./screenshot-widget.png",
                    "sizes": "600x400",
                    "label": "hogehoge"
                }
            ],
            "icons": [
                {
                    "src": "./favicon-16.png",
                    "sizes": "16x16"
                }
            ],
            "auth": false,
            "update": 86400
        }
    ]
}
```
### service-worker.js
```js
self.addEventListener('notificationclick', function (event) {
    event.notification.close();
    event.waitUntil(
        clients.openWindow('https://example.com')
    );
});
```
### favicon-16.png
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778018/d82b64cc-07a2-4482-9dbb-cec5d5c7edc8.png)
### screenshot-widget.png
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3778018/500ca2e4-aced-4ddd-af34-a8193b5246ad.png)

### ./widgets/[任意のファイル名-レイアウト].json
body部分は以下のサイトで作成できるらしい。

https://adaptivecards.io/designer/

データファイルの値を呼び出したいときは、```${変数名}```とすると、更新時にその値となる。
```json
{
    "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
    "type": "AdaptiveCard",
    "version": "1.2",
    "body": [
    ],
    "actions": [
        {
            "type": "Action.OpenUrl",
            "title": "Open",
            "url": "https://example.com"
        }
    ]
}
```
### ./widgets/[任意のファイル名-データ].json
```json
{
    "変数名":"value",
    "変数名2":"value2",
}
```
# 躓いたポイント
* 普段はchromeを使っているが、そもそもEdgeでPWAをインストールしないと動かない
* PWAを配布するサーバーがhttps通信を行っていないといけない(私はGitHub Pagesを使いました。)
* PWAをインストールしたのにウィジェット一覧にない！
  ⇒ウィジェット画面の歯車マークから「新しいウィジェットの検出」を実行してみる
# 実際に開発する際の注意点
* service-worker.jsは常時実装されるわけではなさそう
* 権限的な問題でwindowsの情報にはあまりアクセスできない
* 音声の再生などはできない
* PWAのアプリ起動時のみ動作する？(バックグラウンドも可能のようだが一筋縄ではいかなそう)

# おわりに
今回はPWA駆動型のウィジェットの作成をしました。
ほんとうに参考資料が少なく、PWA化しても認識されずに挫折することが3度ほどありました。
できることは少なそうですが、予定の表示、SNSの通知、時間割の確認など、「見せるだけ」の用途に使う分には有用なのかなと思います。ショートカットキーで呼び出せますし。