Periodic Background Sync API によるオフライン エクスペリエンスの拡充

ウェブアプリのデータをバックグラウンドで同期して、アプリのようなエクスペリエンスを実現する

次のいずれかの状況に遭遇したことがありますか?

  • 電車や地下鉄に乗っていて、接続が不安定または接続されていない
  • 動画を視聴しすぎたため、携帯通信会社によって通信速度が制限されている
  • 帯域幅が需要に追いつかない国に居住している

ウェブで特定の作業を行う際に、不満を感じたことがあるでしょう。また、このようなシナリオでプラットフォーム固有のアプリが優れている理由を疑問に思ったことがあるでしょう。プラットフォーム固有のアプリは、ニュース記事や天気情報などの最新のコンテンツを事前に取得できます。地下鉄でネットワークがなくても、ニュースを読むことができます。

定期的なバックグラウンド同期を使用すると、ウェブ アプリケーションはバックグラウンドでデータを定期的に同期できるため、ウェブアプリの動作がプラットフォーム固有のアプリの動作に近づきます。

試してみる

定期的なバックグラウンド同期は、ライブデモアプリで試すことができます。使用前に、次の点を確認してください。

  • Chrome 80 以降を使用している。
  • 定期的なバックグラウンド同期を有効にする前に、ウェブアプリをインストールします。

コンセプトと使用方法

定期的なバックグラウンド同期を使用すると、プログレッシブ ウェブアプリまたはサービス ワーカーがサポートするページが起動されたときに最新のコンテンツを表示できます。アプリやページが使用されていないときにバックグラウンドでデータをダウンロードすることで、この処理が行われます。これにより、アプリのコンテンツが起動後に更新され、表示中に更新されなくなります。さらに、更新前にアプリがコンテンツ スピナーを表示するのを防ぐことができます。

定期的なバックグラウンド同期がない場合、ウェブアプリは別の方法でデータをダウンロードする必要があります。一般的な例としては、プッシュ通知を使用してサービス ワーカーを起動する方法があります。「新しいデータが利用可能」などのメッセージが表示されて、ユーザーの操作が中断される。データの更新は基本的に副作用です。ただし、重要なニュース速報など、本当に重要な最新情報については、引き続きプッシュ通知を使用できます。

定期的なバックグラウンド同期は、バックグラウンド同期と混同されがちです。名前は似ていますが、ユースケースは異なります。バックグラウンド同期は、以前のリクエストが失敗したときにサーバーにデータを再送信するために最もよく使用されます。

ユーザー エンゲージメントを高める

定期的なバックグラウンド同期を誤って行うと、ユーザーのリソースを浪費する可能性があります。リリースする前に、Chrome ではこの機能の適切性を確認するためのトライアル期間を設けました。このセクションでは、この機能を可能な限り便利にするために Chrome が行った設計上の決定について説明します。

Chrome で最初に行われた設計上の決定は、ウェブアプリは、ユーザーがデバイスにインストールし、個別のアプリとして起動した後にのみ、定期的なバックグラウンド同期を使用できることです。定期的なバックグラウンド同期は、Chrome の通常のタブのコンテキストでは使用できません。

さらに、Chrome では、使用されていないウェブアプリや使用頻度の低いウェブアプリがバッテリーやデータを不必要に消費しないようにするため、定期的なバックグラウンド同期をデベロッパーがユーザーに価値を提供することで獲得できるように設計しています。具体的には、Chrome はサイト エンゲージメント スコアabout://site-engagement/)を使用して、特定のウェブアプリで定期的なバックグラウンド同期が発生するかどうか、発生する場合はその頻度を判断します。つまり、エンゲージメント スコアがゼロより大きい場合を除き、periodicsync イベントはまったく発生しません。また、その値は periodicsync イベントが発生する頻度に影響します。これにより、バックグラウンドで同期されるアプリは、アクティブに使用しているアプリのみになります。

定期的なバックグラウンド同期は、一般的なプラットフォームの既存の API や手法と類似しています。たとえば、1 回限りのバックグラウンド同期やプッシュ通知を使用すると、ユーザーがページを閉じた後も、ウェブアプリのロジックを(サービス ワーカーを介して)もう少し長く維持できます。ほとんどのプラットフォームでは、重要なアップデート、コンテンツのプリフェッチ、データの同期などのユーザー エクスペリエンスを向上させるため、バックグラウンドで定期的にネットワークにアクセスするアプリがインストールされています。同様に、定期的なバックグラウンド同期により、ウェブアプリのロジックの存続期間が延長され、定期的に数分間実行されるようになります。

ブラウザでこの処理が頻繁に制限なく行われると、プライバシーに関する懸念が生じる可能性があります。Chrome では、定期的なバックグラウンド同期に関するこのリスクを次のように対処しています。

  • バックグラウンド同期アクティビティは、デバイスが以前に接続したネットワークでのみ行われます。信頼できる事業者が運営するネットワークにのみ接続することをおすすめします。
  • すべてのインターネット通信と同様に、定期的なバックグラウンド同期では、クライアントの IP アドレス、通信先のサーバー、サーバーの名が明らかになります。このような露出を、アプリがフォアグラウンドにあるときのみ同期する場合とほぼ同じ程度に抑えるために、ブラウザはアプリのバックグラウンド同期の頻度を、ユーザーがそのアプリを使用する頻度に合わせて制限します。ユーザーがアプリの操作を頻繁に行わなくなった場合、定期的なバックグラウンド同期はトリガーされなくなります。これは、プラットフォーム固有のアプリの現状よりも大幅な改善です。

使用できる状況

使用ルールはブラウザによって異なります。上記をまとめると、Chrome では定期的なバックグラウンド同期に次の要件が適用されます。

  • 特定のユーザー エンゲージメント スコア。
  • 以前に使用したネットワークの存在。

同期のタイミングはデベロッパーが制御できません。同期頻度は、アプリの使用頻度に合わせて調整します。(現時点では、プラットフォーム固有のアプリではこの処理が行われません)。また、デバイスの電源と接続状態も考慮されます。

使用する状況

サービス ワーカーが起動して periodicsync イベントを処理するときに、データをリクエストする機会がありますが、リクエストする義務はありません。イベントを処理する際は、ネットワークの状態と使用可能なストレージを考慮し、応答として異なる量のデータをダウンロードする必要があります。次のリソースもご利用ください。

権限

サービス ワーカーをインストールしたら、Permissions API を使用して periodic-background-sync をクエリします。これは、ウィンドウまたはサービス ワーカーのコンテキストから行えます。

const status = await navigator.permissions.query({
  name: 'periodic-background-sync',
});
if (status.state === 'granted') {
  // Periodic background sync can be used.
} else {
  // Periodic background sync cannot be used.
}

定期的同期の登録

前述のように、定期的なバックグラウンド同期には Service Worker が必要です。ServiceWorkerRegistration.periodicSync を使用して PeriodicSyncManager を取得し、register() を呼び出します。登録には、タグと最小同期間隔(minInterval)の両方が必要です。タグは、登録された同期を識別するため、複数の同期を登録できます。次の例では、タグ名は 'content-sync' で、minInterval は 1 日です。

const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
  try {
    await registration.periodicSync.register('content-sync', {
      // An interval of one day.
      minInterval: 24 * 60 * 60 * 1000,
    });
  } catch (error) {
    // Periodic background sync cannot be used.
  }
}

登録の確認

periodicSync.getTags() を呼び出して、登録タグの配列を取得します。次の例では、タグ名を使用してキャッシュ更新が有効になっていることを確認して、再度更新されないようにしています。

const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
  const tags = await registration.periodicSync.getTags();
  // Only update content if sync isn't set up.
  if (!tags.includes('content-sync')) {
    updateContentOnPageLoad();
  }
} else {
  // If periodic background sync isn't supported, always update.
  updateContentOnPageLoad();
}

getTags() を使用して、ウェブアプリの設定ページに有効な登録のリストが表示されるようにし、ユーザーが特定のタイプの更新を有効または無効にできるようにすることもできます。

定期的なバックグラウンド同期イベントへの対応

定期的なバックグラウンド同期イベントに応答するには、Service Worker に periodicsync イベント ハンドラを追加します。渡される event オブジェクトには、登録時に使用された値に一致する tag パラメータが含まれます。たとえば、定期的なバックグラウンド同期が 'content-sync' という名前で登録されている場合、event.tag'content-sync' になります。

self.addEventListener('periodicsync', (event) => {
  if (event.tag === 'content-sync') {
    // See the "Think before you sync" section for
    // checks you could perform before syncing.
    event.waitUntil(syncContent());
  }
  // Other logic for different tags as needed.
});

同期の登録解除

登録済みの同期を終了するには、登録解除する同期の名前を指定して periodicSync.unregister() を呼び出します。

const registration = await navigator.serviceWorker.ready;
if ('periodicSync' in registration) {
  await registration.periodicSync.unregister('content-sync');
}

インターフェース

Periodic Background Sync API が提供するインターフェースについて簡単に説明します。

  • PeriodicSyncEvent。ブラウザが選択した時点で ServiceWorkerGlobalScope.onperiodicsync イベント ハンドラに渡されます。
  • PeriodicSyncManager。定期的な同期の登録と登録解除を行い、登録された同期のタグを提供します。ServiceWorkerRegistration.periodicSync プロパティからこのクラスのインスタンスを取得します。
  • ServiceWorkerGlobalScope.onperiodicsyncPeriodicSyncEvent を受信するハンドラを登録します。
  • ServiceWorkerRegistration.periodicSyncPeriodicSyncManager への参照を返します。

コンテンツの更新

次の例では、定期的なバックグラウンド同期を使用して、ニュース サイトまたはブログの最新記事をダウンロードしてキャッシュに保存します。タグ名に注目してください。これは、この同期の種類('update-articles')を示しています。updateArticles() の呼び出しは event.waitUntil() でラップされているため、記事がダウンロードされて保存される前にサービス ワーカーが終了することはありません。

async function updateArticles() {
  const articlesCache = await caches.open('articles');
  await articlesCache.add('/api/articles');
}

self.addEventListener('periodicsync', (event) => {
  if (event.tag === 'update-articles') {
    event.waitUntil(updateArticles());
  }
});

既存のウェブアプリに定期的なバックグラウンド同期を追加する

既存の PWA に定期的なバックグラウンド同期を追加するには、この一連の変更が必要でした。この例には、ウェブアプリの定期的なバックグラウンド同期の状態を記述する便利なロギング ステートメントがいくつか含まれています。

デバッグ

ローカルでテストする際に、定期的なバックグラウンド同期のエンドツーエンド ビューを取得するのは難しい場合があります。アクティブな登録、概算の同期間隔、過去の同期イベントのログに関する情報は、ウェブアプリの動作をデバッグする際に貴重なコンテキストを提供します。幸い、Chrome DevTools の試験運用版機能で、これらの情報をすべて確認できます。

ローカル アクティビティの記録

DevTools の [定期的なバックグラウンド同期] セクションは、定期的なバックグラウンド同期のライフサイクルの主要なイベント(同期の登録、バックグラウンド同期の実行、登録解除)を中心に構成されています。これらのイベントに関する情報を取得するには、[録画を開始] をクリックします。

DevTools の記録ボタン
Chrome DevTools の記録ボタン

記録中、イベントに対応するエントリが DevTools に表示され、それぞれにコンテキストとメタデータが記録されます。

記録された定期的なバックグラウンド同期データの例
記録された定期的なバックグラウンド同期データの例

一度有効にすると、最大 3 日間有効なままになります。これにより、DevTools は、数時間後でも発生する可能性のあるバックグラウンド同期に関するローカル デバッグ情報をキャプチャできます。

イベントをシミュレートする

バックグラウンド アクティビティの記録は便利ですが、通常の頻度でイベントが発生するのを待たずに、periodicsync ハンドラをすぐにテストしたい場合があります。

これは、Chrome DevTools の [Application] パネルの [Service Workers] セクションで確認できます。[定期的同期] フィールドでは、使用するイベントのタグを指定し、イベントを任意の数だけトリガーできます。

[アプリケーション] パネルの [Service Workers] セクションに、[定期同期] テキスト フィールドとボタンが表示されます。

DevTools インターフェースの使用

Chrome 81 以降では、DevTools の [Application] パネルに [Periodic Background Sync] セクションが表示されます。

[定期的なバックグラウンド同期] セクションが表示された [アプリケーション] パネル