Service Worker がオフラインで機能するページをブラウザに指示できるようにする
Content Indexing API とは
プログレッシブ ウェブアプリを使用すると、ネットワーク接続の現在の状態に関係なく、画像、動画、記事など、ユーザーが関心を持っている情報にアクセスできます。Service Worker、Cache Storage API、IndexedDB などのテクノロジーは、ユーザーが PWA を直接操作するときに、データを保存して提供するための構成要素を提供します。しかし、高品質のオフラインファースト PWA の構築は、ほんの一部にすぎません。ウェブアプリのコンテンツがオフラインでも利用できることを知らなければ、その機能を実装するために費やした労力を十分に活用することはできません。
これは検出の問題です。PWA がオフライン対応コンテンツをユーザーに認識して、利用可能なコンテンツを発見して表示できるようにするには、どうすればよいでしょうか。Content Indexing API は、この問題を解決するための手段です。このソリューションのデベロッパー向けの部分は、Service Worker の拡張機能です。これにより、オフライン対応のページの URL とメタデータをブラウザが管理するローカル インデックスに追加できます。この機能は Chrome 84 以降でご利用いただけます。
PWA およびインストールされているその他の PWA のコンテンツがインデックスに入力されると、ブラウザは以下のように表示されます。
また、ユーザーがオフラインであることが検出されると、おすすめのコンテンツが自動的に表示されます。
Content Indexing API は、コンテンツをキャッシュに保存する別の方法ではありません。これは、Service Worker によってすでにキャッシュに保存されているページに関するメタデータを提供する方法です。これにより、ブラウザは、ユーザーが閲覧する可能性が高いときにそれらのページを表示できます。Content Indexing API は、キャッシュに保存されたページの検出可能性に役立ちます。
実例を見る
Content Indexing API に慣れるには、サンプル アプリケーションを試すことをおすすめします。
- サポートされているブラウザとプラットフォームを使用していることを確認します。現時点では、Android 版 Chrome 84 以降が対象となります。実行中の Chrome のバージョンを確認するには、
about://version
に移動してください。 - https://contentindex.dev にアクセスします。
- リスト内の 1 つ以上のアイテムの横にある [
+
] ボタンをクリックします。 - (省略可)デバイスの Wi-Fi とモバイルデータ接続を無効にするか、機内モードを有効にして、ブラウザがオフラインになることをシミュレートします。
- Chrome のメニューから [ダウンロード] を選択し、[おすすめの記事] タブに切り替えます。
- 以前に保存したコンテンツを参照します。
GitHub でサンプル アプリケーションのソースを確認できます。
別のサンプル アプリケーションであるスクラップブック PWA では、Web Share Target API とともに Content Indexing API を使用する方法を説明しています。このコードは、Cache Storage API を使用して、ウェブアプリで保存したアイテムと Content Indexing API の同期を維持するための手法を示しています。
API の使用
この API を使用するには、オフラインでも移動できる Service Worker と URL がアプリに必要です。ウェブアプリに Service Worker がない場合は、ワークボックス ライブラリで Service Worker を簡単に作成できます。
オフライン対応としてインデックスに登録できる URL のタイプはどれですか。
API では、HTML ドキュメントに対応する URL のインデックス登録がサポートされています。たとえば、キャッシュに保存されたメディア ファイルの URL を直接インデックスに登録することはできません。代わりに、メディアを表示し、オフラインで機能するページの URL を指定する必要があります。
推奨されるパターンは、基盤となるメディア URL をクエリ パラメータとして受け取ることができる「ビューア」HTML ページを作成し、ファイルの内容を表示することです。追加のコントロールやコンテンツをページに追加することもできます。
ウェブアプリは、現在の Service Worker のスコープにある URL のみをコンテンツ インデックスに追加できます。つまり、ウェブアプリで完全に異なるドメインに属する URL をコンテンツ インデックスに追加することはできません。
概要
Content Indexing API は、メタデータの追加、一覧表示、削除という 3 つの操作をサポートしています。これらのメソッドは、ServiceWorkerRegistration
インターフェースに追加された新しいプロパティ index
から公開されます。
コンテンツをインデックスに登録する最初のステップは、現在の ServiceWorkerRegistration
への参照を取得することです。navigator.serviceWorker.ready
を使用するのが最も簡単な方法です。
const registration = await navigator.serviceWorker.ready;
// Remember to feature-detect before using the API:
if ('index' in registration) {
// Your Content Indexing API code goes here!
}
ウェブページ内ではなく、Service Worker 内から Content Indexing API を呼び出す場合は、registration
を介して ServiceWorkerRegistration
を直接参照できます。これは、ServiceWorkerGlobalScope.
の一部としてすでに定義されています。
インデックスへの追加
add()
メソッドを使用して、URL とそれに関連するメタデータをインデックスに登録します。アイテムをインデックスに追加するタイミングは任意です。「オフラインに保存」ボタンのクリックなどの入力に応じてインデックスに追加することもできます。または、定期的なバックグラウンド同期などのメカニズムによって、キャッシュ データが更新されるたびにアイテムを自動的に追加することもできます。
await registration.index.add({
// Required; set to something unique within your web app.
id: 'article-123',
// Required; url needs to be an offline-capable HTML page.
url: '/articles/123',
// Required; used in user-visible lists of content.
title: 'Article title',
// Required; used in user-visible lists of content.
description: 'Amazing article about things!',
// Required; used in user-visible lists of content.
icons: [{
src: '/img/article-123.png',
sizes: '64x64',
type: 'image/png',
}],
// Optional; valid categories are currently:
// 'homepage', 'article', 'video', 'audio', or '' (default).
category: 'article',
});
エントリの追加が影響するのはコンテンツ インデックスのみです。キャッシュには何も追加されません。
エッジケース: アイコンが fetch
ハンドラに依存している場合は、window
コンテキストから add()
を呼び出す
add()
を呼び出すと、Chrome は各アイコンの URL をリクエストして、インデックス登録済みコンテンツのリストを表示するときに使用するアイコンのコピーが含まれるようにします。
window
コンテキスト(つまりウェブページから)からadd()
を呼び出すと、このリクエストによって Service Worker でfetch
イベントがトリガーされます。Service Worker 内(別のイベント ハンドラ内など)で
add()
を呼び出した場合、そのリクエストで Service Worker のfetch
ハンドラはトリガーされません。アイコンは Service Worker の関与なしに直接取得されます。アイコンがfetch
ハンドラに依存している場合は、この点に注意してください。アイコンはローカル キャッシュにのみ存在し、ネットワークには存在しないことが理由と考えられます。その場合は、window
コンテキストからのみadd()
を呼び出すようにしてください。
インデックスの内容の一覧表示
getAll()
メソッドは、インデックス付きエントリとそのメタデータのイテラブル リストに対する Promise を返します。返されるエントリには、add()
で保存されたすべてのデータが含まれます。
const entries = await registration.index.getAll();
for (const entry of entries) {
// entry.id, entry.launchUrl, etc. are all exposed.
}
インデックスからアイテムを削除する
インデックスからアイテムを削除するには、削除するアイテムの id
を指定して delete()
を呼び出します。
await registration.index.delete('article-123');
delete()
の呼び出しはインデックスにのみ影響します。キャッシュからは何も削除されません。
ユーザーの削除イベントの処理
ブラウザがインデックスに登録されたコンテンツを表示すると、独自のユーザー インターフェースと [削除] メニュー項目が表示され、ユーザーは以前にインデックスに登録されたコンテンツを表示したことを通知できます。Chrome 80 での削除インターフェースは次のようになります。
ユーザーがそのメニュー項目を選択すると、ウェブアプリの Service Worker は contentdelete
イベントを受け取ります。このイベントの処理は任意ですが、ローカルにキャッシュされたメディア ファイルなど、ユーザーが処理を完了したことを Service Worker が「クリーンアップ」する機会が得られます。
contentdelete
ハンドラ内で registration.index.delete()
を呼び出す必要はありません。このイベントが発生すると、関連するインデックスの削除はブラウザによってすでに実行されています。
self.addEventListener('contentdelete', (event) => {
// event.id will correspond to the id value used
// when the indexed content was added.
// Use that value to determine what content, if any,
// to delete from wherever your app stores it—usually
// the Cache Storage API or perhaps IndexedDB.
});
API 設計に関するフィードバック
API について、何かおかしい点や、期待どおりに動作しない点はありますか。あるいは、アイデアを実現するために欠けているものがあるか?
Content Indexing API 解説 GitHub リポジトリで問題を報告するか、既存の問題に意見を追加します。
実装に問題がある場合
Chrome の実装にバグが見つかりましたか?
https://new.crbug.com でバグを報告します。できる限り詳細かつ簡単な再現手順を記載し、[Components] を Blink>ContentIndexing
に設定します。
API を使用する予定がある場合は、
ウェブアプリで Content Indexing API を使用する予定がある場合は、公開サポートによって、Chrome が機能に優先順位を付け、そのサポートがいかに重要であるかを他のブラウザ ベンダーに示すことができます。
- ハッシュタグ
#ContentIndexingAPI
と、その使用場所や使用方法の詳細を使用して、@ChromiumDev にツイートを送信してください。
コンテンツのインデックス登録によって、セキュリティとプライバシーにどのような影響がありますか?
W3C のセキュリティとプライバシーに関するアンケートへの回答をご確認ください。ご不明な点がございましたら、プロジェクトの GitHub リポジトリからディスカッションにご参加ください。
ヒーロー画像(作成者: Maksym Kaharlytskyi、Unsplash)