使用 Service Worker 管理通知

Kate Jeffreys
Kate Jeffreys

在本程式碼研究室中,您將使用服務工作者來管理通知。這裡的操作說明假設您已熟悉服務工作站,以及要求通知權限和傳送通知的基本概念。如需複習通知功能,請參閱「開始使用 Notifications API」程式碼研究室。如要進一步瞭解 Service Worker,請參閱 Matt Gaunt 的「Service Worker 簡介」。

系統會自動封鎖內嵌的 Glitch 應用程式通知,因此您無法在這個頁面預覽應用程式。而是可以採取以下做法:

  1. 按一下「Remix to Edit」即可編輯專案。
  2. 如要預覽網站,請按下「View App」。然後按下「Fullscreen」圖示 全螢幕

Glitch 應會在新分頁中開啟。

在本程式碼研究室中,請修改本頁嵌入的 Glitch 中的程式碼。重新整理含有即時應用程式的新分頁,即可查看變更內容。

熟悉範例應用程式和啟動程式碼

首先,請在新的 Chrome 分頁中查看即時應用程式:

  1. 按下 `Control+Shift+J` 鍵 (在 Mac 上為 `Command+Option+J` 鍵) 開啟開發人員工具。
  2. 再按一下「Console」(控制台) 分頁標籤即可。

  3. 請確認您已在「篩選」方塊旁的「層級」下拉式選單中,選取「資訊」選項。

  4. 在線上應用程式的開發人員工具控制台中,您應該會看到以下控制台訊息:

    TODO: Implement getRegistration()

    這是您將在本程式碼研究室中實作的函式輔助程式訊息。

接下來,我們來看看這個頁面中嵌入的 Glitch 中,範例應用程式的程式碼。

  1. 在嵌入式 Glitch 中,查看 public/index.js

    • 您要實作的函式有四個 Stub:registerServiceWorkergetRegistrationunRegisterServiceWorkersendNotification

    • requestPermission 函式會要求使用者授權傳送通知。如果您已完成Notifications API codelab,就會發現這裡使用了 requestPermission 函式。唯一的差異在於,現在也會在解決權限要求後更新使用者介面。

    • updateUI 函式會重新整理應用程式的所有按鈕和訊息。

    • initializePage 函式會在瀏覽器中執行服務工作者功能的功能偵測,並更新應用程式使用者介面。

    • 指令碼會等待頁面載入,然後將其初始化。

  2. 在嵌入的 Glitch 中開啟 public/service-worker.js

    顧名思義,您會在應用程式中新增程式碼,將此檔案註冊為服務工作者

    雖然此檔案尚未由應用程式使用,但包含一些範例程式碼,會在服務工作站啟用時將訊息輸出至主控台。

    您會在 public/service-worker.js 中加入程式碼,以便在服務工作者收到通知時處理通知。

註冊 Service Worker

在這個步驟中,您將編寫程式碼,當使用者在應用程式 UI 中點選「Register Service Worker」時,就會執行此程式碼。這個程式碼會將 public/service-worker.js 註冊為 Service Worker。

  1. 在內嵌的 Glitch 編輯器中開啟 public/index.js。將 registerServiceWorker 函式替換為以下程式碼:

    // Use the Service Worker API to register a service worker.
    async
    function registerServiceWorker() {
      await navigator
    .serviceWorker.register('./service-worker.js')
      updateUI
    ();
    }

    請注意,registerServiceWorker 使用 async function 宣告,讓處理承諾更方便。這樣一來,您就能 await Promise 的解析值。舉例來說,上述函式會等待註冊 Service Worker 的結果再更新 UI。詳情請參閱 MDN 上的 await

  2. 使用者現在可以註冊服務工作者,因此您可以取得服務工作者註冊物件的參照。在 public/index.js 中,將 getRegistration 函式替換為以下程式碼:

    // Get the current service worker registration.
    function getRegistration() {
     
    return navigator.serviceWorker.getRegistration();
    }

    上述函式使用 Service Worker API 取得目前的 Service Worker 註冊 (如果有的話)。如此一來,取得 Service Worker 註冊的參照就更加方便。

  • 如要完成 Service Worker 註冊功能,請新增程式碼來取消註冊 Service Worker。將 unRegisterServiceWorker 函式替換為以下程式碼:

    // Unregister a service worker, then update the UI.
    async
    function unRegisterServiceWorker() {
     
    // Get a reference to the service worker registration.
      let registration
    = await getRegistration();
     
    // Await the outcome of the unregistration attempt
     
    // so that the UI update is not superceded by a
     
    // returning Promise.
      await registration
    .unregister();
      updateUI
    ();
    }

在您觀看直播應用程式的分頁中,重新載入頁面。「Register service worker」和「Unregister service worker」按鈕現在應該可以正常運作。

傳送通知至服務工作者

在這個步驟中,您將編寫程式碼,在使用者點選應用程式 UI 中的「Send a notification」時執行。這個程式碼將建立通知,檢查 Service Worker 是否已註冊,然後使用 postMessage 方法傳送通知給 Service Worker。

在內嵌的 Glitch 編輯器中,開啟 public/index.js,然後將 sendNotification 函式替換為以下程式碼:

// Create and send a test notification to the service worker.
async
function sendNotification() {
 
// Use a random number as part of the notification data
 
// (so you can tell the notifications apart during testing!)
  let randy
= Math.floor(Math.random() * 100);
  let notification
= {
    title
: 'Test ' + randy,
    options
: { body: 'Test body ' + randy }
 
};
 
// Get a reference to the service worker registration.
  let registration
= await getRegistration();
 
// Check that the service worker registration exists.
 
if (registration) {
   
// Check that a service worker controller exists before
   
// trying to access the postMessage method.
   
if (navigator.serviceWorker.controller) {
      navigator
.serviceWorker.controller.postMessage(notification);
   
} else {
      console
.log('No service worker controller found. Try a soft reload.');
   
}
 
}
}

該程式碼的功能如下:

  • sendNotification 是個非同步函式,因此您可以使用 await 取得服務工作者註冊的參照。

  • Service Worker 的 postMessage 方法會將應用程式中的資料傳送至 Service Worker。詳情請參閱 postMessage 的 MDN 說明文件

  • 程式碼會先檢查是否有 navigator.serviceWorker.controller 屬性,再嘗試存取 postMessage 函式。如果沒有任何使用中的 Service Worker,或強制重新整理頁面,navigator.serviceWorker.controller 將為 null (Shift+重新載入)。詳情請參閱 MDN 上的 ServiceWorker 控制器說明文件

在服務工作站中處理通知

在這個步驟中,您將在服務工作者中編寫程式碼,以便處理發布至該服務工作者的訊息,並向使用者顯示通知。

在內嵌的 Glitch 編輯器中開啟 public/service-worker.js。在檔案結尾新增下列程式碼:

// Show notification when received
self
.addEventListener('message', (event) => {
  let notification
= event.data;
  self
.registration.showNotification(
    notification
.title,
    notification
.options
 
).catch((error) => {
    console
.log(error);
 
});
});

以下簡要說明:

  • self 是服務工作者本身的參照。

  • 雖然服務工作者現在會處理顯示通知的作業,但主要應用程式 UI 仍負責取得使用者的通知權限。如果使用者未授予權限,showNotification 回傳的承諾使用合約會遭到拒絕。上述程式碼使用 catch 區塊,避免發生未偵測到的 Promise 拒絕錯誤,並以更妥善的方式處理這項錯誤。

如果卡住了,請參閱 glitch.com/edit/#!/codelab-notifications-service-worker-completed 查看完整程式碼。

請繼續參閱本系列的下一篇程式碼研究室:建構推播通知伺服器