Content Indexing API を使ったオフライン対応ページのインデックス登録

サービス ワーカーを有効にして、オフラインで動作するページをブラウザに通知する

プログレッシブ ウェブアプリを使用すると、ネットワーク接続の現在の状態に関係なく、ユーザーが関心を持つ情報(画像、動画、記事など)にアクセスできます。Service WorkerCache Storage APIIndexedDB などのテクノロジーは、ユーザーが PWA を直接操作する際にデータを保存して提供するための構成要素を提供します。しかし、高品質のオフラインファースト PWA を構築するだけでは十分ではありません。オフラインでもウェブアプリのコンテンツを利用できることをユーザーが認識していないと、その機能を実装するために費やした労力は十分に活用されません。

これは検出の問題です。ユーザーが利用可能なコンテンツを見つけて表示できるように、PWA でオフライン対応コンテンツをユーザーに知らせるにはどうすればよいでしょうか。Content Indexing API は、この問題の解決策です。このソリューションのデベロッパー向け部分は、サービス ワーカーの拡張機能です。これにより、デベロッパーは、オフライン対応ページの URL とメタデータを、ブラウザによって管理されるローカル インデックスに追加できます。この拡張機能は Chrome 84 以降で利用できます。

インデックスに PWA およびインストールされている他の PWA のコンテンツが入力されると、次のようにブラウザに表示されます。

Chrome の新しいタブページの [ダウンロード] メニュー項目のスクリーンショット。
まず、Chrome の新しいタブページで [ダウンロード] メニュー項目を選択します。
インデックスに追加されたメディアと記事。
インデックスに追加されたメディアと記事は、[おすすめの記事] セクションに表示されます。

また、ユーザーがオフラインであることを検出すると、Chrome はコンテンツを事前におすすめできます。

Content Indexing API はコンテンツをキャッシュに保存する代替手段ではありません。これは、サービス ワーカーによってすでにキャッシュに保存されているページに関するメタデータを提供する方法です。これにより、ユーザーが閲覧する可能性が高いときに、ブラウザがそれらのページを表示できます。Content Indexing API は、キャッシュに保存されたページの見つけやすさに役立ちます。

実例を見る

Content Indexing API を理解する最善の方法は、サンプル アプリケーションを試すことです。

  1. サポートされているブラウザとプラットフォームを使用していることを確認します。現在、Android 版 Chrome 84 以降に限定されています。about://version に移動して、実行している Chrome のバージョンを確認します。
  2. https://contentindex.dev にアクセスします。
  3. リスト内の 1 つ以上のアイテムの横にある + ボタンをクリックします。
  4. (省略可)デバイスの Wi-Fi 接続とモバイルデータ接続を無効にするか、機内モードを有効にして、ブラウザをオフラインにすることをシミュレートします。
  5. Chrome のメニューから [ダウンロード] を選択し、[おすすめの記事] タブに切り替えます。
  6. 以前に保存したコンテンツを参照します。

GitHub にあるサンプル アプリケーションのソースを確認する。

もう 1 つのサンプル アプリケーションである Scrapbook PWA では、Web Share Target API とともに Content Indexing API を使用しています。このコードは、Cache Storage API を使用して、Content Indexing API をウェブアプリによって保存されたアイテムと同期させる手法を示しています

API の使用

この API を使用するには、アプリにサービス ワーカーとオフラインで移動可能な URL が必要です。ウェブアプリに Service Worker がない場合は、Workbox ライブラリを使用すると簡単に 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!
}

ウェブページ内ではなく、サービス ワーカー内から 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 イベントがトリガーされます。

  • サービス ワーカー内で(別のイベント ハンドラ内など)add() を呼び出すと、リクエストによってサービス ワーカーの fetch ハンドラがトリガーされることはありません。アイコンは、サービス ワーカーを介さずに直接取得されます。アイコンがネットワーク上に存在せず、ローカル キャッシュにのみ存在するため、アイコンが fetch ハンドラに依存している場合は、この点に注意してください。同じコンテキストで add() を呼び出す場合は、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 は、ローカルにキャッシュされたメディア ファイルなど、処理が完了したと示されたコンテンツを 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 でバグを報告します。できるだけ詳細な情報を含め、再現手順を簡単に説明します。[コンポーネント] を Blink>ContentIndexing に設定します。

API を使用する予定ですか?

ウェブアプリで Content Indexing API を使用する予定ですか?公開サポートは、Chrome の機能の優先順位付けに役立ち、他のブラウザ ベンダーにそれらのサポートの重要性を伝えます。

  • ハッシュタグ #ContentIndexingAPI を使用して、@ChromiumDev にツイートを送信し、使用場所と使用方法の詳細を記載します。

コンテンツのインデックス作成は、セキュリティとプライバシーにどのような影響を与えますか?

W3C のセキュリティとプライバシーに関するアンケートに対する回答を確認してください。他にご不明な点がございましたら、プロジェクトの GitHub リポジトリでディスカッションをお気軽に開始してください。

ヒーロー画像: Unsplash の Maksym Kaharlytskyi 氏