新增推播通知至網頁應用程式

推送訊息可讓您以簡單又有效的方式,再次與使用者進行互動。在這個程式碼研究室中,您將瞭解如何在網路應用程式中新增推播通知。

您將會瞭解的內容

  • 如何訂閱及取消訂閱使用者的簡訊
  • 如何處理收到的訊息
  • 如何顯示通知
  • 如何回應通知點擊次數

軟硬體需求

  • Chrome 52 以上版本
  • Chrome 網路伺服器或您自己的網路伺服器
  • 文字編輯器
  • HTML、CSS、JavaScript 和 Chrome 開發人員工具的基本知識
  • 範例程式碼 (請參閱「進行設定」)。

下載範例程式碼

您可以透過兩種方式,取得這個程式碼研究室的範例程式碼:

  • 複製 Git 存放區:
git clone https://github.com/GoogleChrome/push-notifications.git
  • 下載 ZIP 檔案:

下載原始碼

如果您以 ZIP 檔案格式下載來源檔案,則解壓縮後,系統會提供一個根資料夾 push-notifications-master

安裝並驗證網路伺服器

儘管您可以免費使用自己的網路伺服器,但這個程式碼研究室是專為 Chrome 網路應用程式的 Chrome 應用程式所設計。如果您尚未安裝這個應用程式,可以前往 Chrome 線上應用程式商店下載:

安裝 Chrome 專用的 Web Server

安裝 Chrome 網路應用程式 Chrome 版應用程式後,請按一下書籤列的 [應用程式] 捷徑:

在「Apps」視窗中,按一下「Web Server」圖示:

接下來會出現這個對話方塊,供您設定本機網路伺服器:

按一下 [選擇資料夾] 按鈕,然後在您下載的 push-notifications 資料夾中選取 app 資料夾。如此一來,您就可以透過對話方塊顯示的「網路伺服器網址」部分顯示的網址,

在「選項」之下,勾選 [自動顯示 index.html] 旁邊的方塊,如下所示:

然後將 [網路伺服器:STARTED] 開關往左移,接著往右滑動,即可停止伺服器並重新啟動。

按一下 [網路伺服器網址] 即可在網路瀏覽器中造訪您的網站。你應該看到如下所示的頁面:不過你的版本可能會顯示 127.0.0.1:8887 這個位址:

00-push-codelab.png

一律更新服務工作站

在開發期間,請確保服務業者隨時保持在最新狀態,並且掌握最新的變更。

如要在 Chrome 中進行設定,請按照下列步驟操作:

  1. 前往「Push Codelab」分頁。
  2. 開啟開發人員工具:Windows 和 Linux 系統為 Ctrl-Shift-I 鍵,macOS 則為 Cmd-Option-I 鍵。
  3. 選擇 [Application] (應用程式) 面板,然後按一下 [Service Workers] (服務工作站) 分頁標籤,然後勾選 [重新載入時更新] 核取方塊。勾選這個核取方塊後,系統就會在每次網頁載入時強制更新 Service Worker。

已完成的程式碼

請注意,您的 app 目錄中有一個名為「sw.js」的空白檔案。這個檔案將是您的服務業者。現在,它可以保持空白。您稍後就能在其中新增程式碼。

首先,您必須將這個檔案註冊為 Service Worker。

您的 app/index.html 頁面載入了 scripts/main.js。您會在這個 JavaScript 檔案中註冊 Service Worker。

將下列程式碼加進 scripts/main.js

if ('serviceWorker' in navigator && 'PushManager' in window) {
  console.log('Service Worker and Push are supported');

  navigator.serviceWorker.register('sw.js')
  .then(function(swReg) {
    console.log('Service Worker is registered', swReg);

    swRegistration = swReg;
  })
  .catch(function(error) {
    console.error('Service Worker Error', error);
  });
} else {
  console.warn('Push messaging is not supported');
  pushButton.textContent = 'Push Not Supported';
}

瀏覽器會檢查瀏覽器是否支援服務工作人員和推送訊息。如果支援的話,程式碼會註冊您的 sw.js 檔案。

實戰演練

如要重新整理變更,請在瀏覽器中重新整理 [Push Codelab] 分頁。

檢查 Chrome 開發人員工具中的主控台是否出現 Service Worker is registered message,如下所示:

取得應用程式伺服器金鑰

如要使用這個程式碼研究室,您必須產生應用程式伺服器金鑰。您可以在隨附網站上執行此動作:web-push-codelab.glitch.me

您可以在這裡產生公開和私密金鑰組。

push-codelab-04-companion.png

將公開金鑰複製到 scripts/main.js,取代 <Your Public Key> 值:

const applicationServerPublicKey = '<Your Public Key>';

重要:請絕對不要將私密金鑰放在網頁應用程式中!

已完成的程式碼

目前,網路應用程式的 [啟用] 按鈕已停用,且無法點選。這是因為根據預設,瀏覽器會停用推送按鈕,而您知道瀏覽器是否支援推送訊息功能。此外,您也可以查看使用者目前是否訂閱訊息。

您必須在 scripts/main.js 中建立兩個函式:

  • initializeUI:查看使用者是否目前已訂閱
  • updateBtn:即可啟用按鈕,並根據使用者是否訂閱而變更文字

main.js 中加入 initializeUI 函式,如下所示:

function initializeUI() {
  // Set the initial subscription value
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    isSubscribed = !(subscription === null);

    if (isSubscribed) {
      console.log('User IS subscribed.');
    } else {
      console.log('User is NOT subscribed.');
    }

    updateBtn();
  });
}

新方法使用前一步驟中的 swRegistration,從中取得 pushManager 屬性,然後呼叫 getSubscription()

pushManager。「getSubscription()」會傳回一個承諾使用現有訂閱項目來解決相關問題。否則,會傳回 null。您可以在此確認使用者是否已訂閱、設定 isSubscribed 的值,然後呼叫 updateBtn() 以更新按鈕。

updateBtn() 函式新增至 main.js

function updateBtn() {
  if (isSubscribed) {
    pushButton.textContent = 'Disable Push Messaging';
  } else {
    pushButton.textContent = 'Enable Push Messaging';
  }

  pushButton.disabled = false;
}

這項功能會啟用按鈕,並根據使用者是否訂閱而變更按鈕文字。

最後,系統會在您的服務工作人員在 main.js 註冊時呼叫 initializeUI()

navigator.serviceWorker.register('sw.js')
.then(function(swReg) {
  console.log('Service Worker is registered', swReg);

  swRegistration = swReg;
  initializeUI();
})

實戰演練

重新整理「Push Codelab」分頁。系統應該已經啟用 [Enable Push Messaging] (啟用推送訊息) 按鈕 (您可以點選該按鈕),您應該會在主控台中看到 User is NOT subscribed

在這個程式碼研究室的其餘部分,您應該會在訂閱或取消訂閱時,變更按鈕文字。

已完成的程式碼

目前系統還無法啟用推播訊息按鈕。我們來修正問題。

initializeUI() 函式中,為您的按鈕新增點擊事件監聽器:

function initializeUI() {
  pushButton.addEventListener('click', function() {
    pushButton.disabled = true;
    if (isSubscribed) {
      // TODO: Unsubscribe user
    } else {
      subscribeUser();
    }
  });

  // Set the initial subscription value
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    isSubscribed = !(subscription === null);

    updateSubscriptionOnServer(subscription);

    if (isSubscribed) {
      console.log('User IS subscribed.');
    } else {
      console.log('User is NOT subscribed.');
    }

    updateBtn();
  });
}

使用者點選按鈕後,您只是停用了該按鈕,確保使用者無法再次點擊按鈕,因為訂閱推送訊息可能需要一些時間。

然後,如果使用者目前並未訂閱,您就會呼叫 subscribeUser()。若要這麼做,您需將下列程式碼貼到 scripts/main.js 中:

function subscribeUser() {
  const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
  swRegistration.pushManager.subscribe({
    userVisibleOnly: true,
    applicationServerKey: applicationServerKey
  })
  .then(function(subscription) {
    console.log('User is subscribed.');

    updateSubscriptionOnServer(subscription);

    isSubscribed = true;

    updateBtn();
  })
  .catch(function(error) {
    console.error('Failed to subscribe the user: ', error);
    updateBtn();
  });
}

讓我們逐步瞭解這個程式碼的作用,以及它如何訂閱使用者的推送訊息。

首先,您會取得應用程式伺服器的公開金鑰 (Base64 URL 安全編碼),並將其轉換為 UInt8Array,因為這是 subscribe() 呼叫的預期輸入內容。urlB64ToUint8Array() 函式位於 scripts/main.js 頂端。

轉換這個值後,您可以在服務工作站的 pushManager 上呼叫 subscribe() 方法,傳入應用程式伺服器的公開金鑰和 userVisibleOnly: true 值。

const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
swRegistration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: applicationServerKey
})

userVisibleOnly 參數可確保您在傳送推送訊息時一律顯示通知。目前,這是必要值,且必須是 true。

呼叫 subscribe() 會傳回承諾,而該步驟將執行,步驟如下:

  1. 使用者已授予顯示通知的權限。
  2. 瀏覽器已向網路服務傳送網路要求,以便取得產生 PushSubscription 所需的資料。

如果成功,PushSubscription 將透過 subscribe() 解決。如果使用者未授予權限,或者在使用者訂閱時發生問題,承諾拒絕要求就會遭到拒絕。這樣即可在程式碼研究室中取得下列承諾使用鏈:

swRegistration.pushManager.subscribe({
  userVisibleOnly: true,
  applicationServerKey: applicationServerKey
})
.then(function(subscription) {
  console.log('User is subscribed.');

  updateSubscriptionOnServer(subscription);

  isSubscribed = true;

  updateBtn();

})
.catch(function(err) {
  console.log('Failed to subscribe the user: ', err);
  updateBtn();
});

您可以藉此取得約期授權,並將使用者視為已訂閱,或是發生錯誤並記錄控制台。在這兩種情況下,您都會呼叫 updateBtn() 來確保按鈕已重新啟用,且包含適當的文字。

在實際應用程式中,updateSubscriptionOnServer() 函式可讓您將訂閱資料傳送至後端,但如果是程式碼研究室,您只要直接在 UI 中顯示訂閱即可。將下列函式新增至 scripts/main.js

function updateSubscriptionOnServer(subscription) {
  // TODO: Send subscription to application server

  const subscriptionJson = document.querySelector('.js-subscription-json');
  const subscriptionDetails =
    document.querySelector('.js-subscription-details');

  if (subscription) {
    subscriptionJson.textContent = JSON.stringify(subscription);
    subscriptionDetails.classList.remove('is-invisible');
  } else {
    subscriptionDetails.classList.add('is-invisible');
  }
}

實戰演練

前往 [Push Codelab] (推送程式碼研究室) 分頁,重新整理頁面,然後按一下按鈕。這時畫面上會出現下列權限提示:

如果您授予權限,主控台上應該會顯示「User is subscribed」。該按鈕的文字會變更為 [停用推送訊息],您將可以在頁面底部以 JSON 資料的形式查看訂閱。

已完成的程式碼

您尚未處理權限要求,就是當使用者封鎖權限要求時,會發生什麼情況。這項設定需要特別注意,因為如果使用者封鎖權限,您的網頁應用程式將無法重新顯示權限提示,而且使用者無法訂閱。您必須至少停用按鈕,讓使用者知道無法使用。

處理此情況的顯而易見,是位於 updateBtn() 函式中。您只需要檢查 Notification.permission 值,如下所示:

function updateBtn() {
  if (Notification.permission === 'denied') {
    pushButton.textContent = 'Push Messaging Blocked';
    pushButton.disabled = true;
    updateSubscriptionOnServer(null);
    return;
  }

  if (isSubscribed) {
    pushButton.textContent = 'Disable Push Messaging';
  } else {
    pushButton.textContent = 'Enable Push Messaging';
  }

  pushButton.disabled = false;
}

您知道權限是 denied,表示使用者無法訂閱,而且無法採取其他行動,因此永久停用按鈕是最好的方法。

實戰演練

由於您已經在上一個步驟中授權了網頁應用程式,因此需要按一下網址列中圓圈中的 [i],並將「通知」權限變更為 [使用全域預設 (詢問)]

變更這項設定後,請重新整理頁面,然後按一下 [啟用推送訊息] 按鈕,然後在權限對話方塊中選取 [封鎖]。這個按鈕將停用,並顯示「禁止發送簡訊」文字。

本次異動生效後,您現在可以將使用者訂閱,並處理可能的權限情境。

已完成的程式碼

在瞭解如何傳送後端推送訊息之前,您必須考量訂閱使用者收到推送訊息的實際狀況。

當您觸發推送訊息時,瀏覽器會接收推送訊息,並判斷推送工作的目標服務工作站、喚醒該服務工作站,以及分派推送事件。您必須監聽這個事件,系統才會顯示通知。

請將下列程式碼新增到 sw.js 檔案中:

self.addEventListener('push', function(event) {
  console.log('[Service Worker] Push Received.');
  console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);

  const title = 'Push Codelab';
  const options = {
    body: 'Yay it works.',
    icon: 'images/icon.png',
    badge: 'images/badge.png'
  };

  event.waitUntil(self.registration.showNotification(title, options));
});

我們來逐步瀏覽這個程式碼。您可以新增事件監聽器,藉此監聽服務工作站中的 push 個事件:

self.addEventListener('push', ... );

(除非您之前已經與 Web Workers 互動,否則 self 可能是新的應用程式。在 Service Worker 檔案中,self 會參照 Service Worker 本身。)

當系統收到推送訊息時,系統會呼叫事件監聽器,而您可以在服務工作人員的 registration 屬性上呼叫 showNotification() 以建立通知。「showNotification()」需要「title」;您也可以為其指派 options 物件,以設定內文、圖示和標記。(只有 Android 撰寫時可使用徽章)。

const title = 'Push Codelab';
const options = {
  body: 'Yay it works.',
  icon: 'images/icon.png',
  badge: 'images/badge.png'
};
self.registration.showNotification(title, options);

push」事件處理作業的最後一步是「event.waitUntil()」。這個方法會保證瀏覽器啟用服務工作站,讓服務工作人員持續運作,直到傳遞承諾已解決為止。

為了讓程式碼更容易理解,您可以改寫程式碼:

const notificationPromise = self.registration.showNotification(title, options);
event.waitUntil(notificationPromise);

現在您已經完成推送事件,接著來測試推送事件。

實戰演練

在服務工作站中使用推送事件處理功能,您可以觸發偽造的推送事件,以測試收到訊息時會發生什麼事。

在您的網頁應用程式中訂閱推送訊息,並確認主控台顯示「User IS subscribed」。在開發人員工具的「Application」(應用程式) 面板中,按一下「Service Workers」(服務工作站) 分頁下的 [Push] (推送) 按鈕:

按下 [推送] 後,您應該會看到類似以下的通知:

注意:如果這個步驟無法執行,請嘗試使用「開發人員工具」應用程式面板中的 [取消註冊] 連結取消註冊服務工作站,等待服務人員停止,然後重新載入頁面。

已完成的程式碼

只要按一下其中一則通知,您就會發現沒有任何事。監聽服務工作站中的 notificationclick 事件,即可處理通知點擊。

首先,在 sw.js 中新增 notificationclick 事件監聽器:

self.addEventListener('notificationclick', function(event) {
  console.log('[Service Worker] Notification click received.');

  event.notification.close();

  event.waitUntil(
    clients.openWindow('https://developers.google.com/web')
  );
});

使用者點擊通知時,系統會呼叫 notificationclick 事件監聽器。

程式碼首先會關閉所點擊的通知:

event.notification.close();

接著開啟新視窗或新分頁,載入網址 https://developers.google.com/web。可以變更這項設定。

event.waitUntil(
    clients.openWindow('https://developers.google.com/web/')
  );

event.waitUntil() 會確保瀏覽器在顯示新視窗或新分頁之前,才終止服務工作站。

實戰演練

再次嘗試在開發人員工具中觸發推送訊息,然後點選通知。系統隨即將關閉通知功能,並會開啟新分頁。

您發現自己的網頁應用程式能夠使用開發人員工具顯示通知,也想瞭解如何點擊關閉通知。下一步是傳送實際的推送訊息。

一般而言,這需要從網頁傳送訂閱到後端。接著,後端會藉由對訂閱項目中的端點發出 API 呼叫來觸發推送訊息。

這超出此程式碼研究室的範圍,但您可以透過夥伴網站 (web-push-codelab.glitch.me) 觸發實際的推送訊息。將訂閱項目貼到頁面底部:

然後貼到「訂閱收件者」文字區域中的隨播廣告素材網站:

在「Text to Send」(要傳送的文字) 之下,新增您要透過推送訊息傳送的字串。

按一下 [傳送推送訊息] 按鈕。

你隨即會收到推播通知。您使用的文字會記錄在控制台中。

如此一來,您就能測試及接收資料,並且操控搜尋結果。

隨附應用程式是使用 web-push 程式庫傳送訊息的節點伺服器。建議您查看 GitHub 上的 web-push-libs 機構,看看有哪些程式庫可以傳送推送訊息給您。這樣可以處理許多詳細資料,以觸發推送訊息。

您可以前往這裡查看隨播廣告網站的所有程式碼。

已完成的程式碼

但有一件事是能夠讓使用者取消訂閱,方法是呼叫 PushSubscription 上的 unsubscribe()

返回您的 scripts/main.js 檔案,將 initializeUI() 中的 pushButton 點擊接聽器變更為以下內容:

pushButton.addEventListener('click', function() {
  pushButton.disabled = true;
  if (isSubscribed) {
    unsubscribeUser();
  } else {
    subscribeUser();
  }
});

請注意,您將會呼叫新的函式 unsubscribeUser()。在這個函式中,您會取得目前的訂閱項目並呼叫 unsubscribe()。將下列程式碼加進 scripts/main.js

function unsubscribeUser() {
  swRegistration.pushManager.getSubscription()
  .then(function(subscription) {
    if (subscription) {
      return subscription.unsubscribe();
    }
  })
  .catch(function(error) {
    console.log('Error unsubscribing', error);
  })
  .then(function() {
    updateSubscriptionOnServer(null);

    console.log('User is unsubscribed.');
    isSubscribed = false;

    updateBtn();
  });
}

我們來逐步說明這個函式。

首先,您可以呼叫 getSubscription(),取得目前的訂閱:

swRegistration.pushManager.getSubscription()

這會傳回承諾使用 PushSubscription 解析的承諾產品;否則傳回 null。如有訂閱項目,請呼叫 unsubscribe(),讓 PushSubscription 無效。

swRegistration.pushManager.getSubscription()
.then(function(subscription) {
  if (subscription) {
    // TODO: Tell application server to delete subscription
    return subscription.unsubscribe();
  }
})
.catch(function(error) {
  console.log('Error unsubscribing', error);
})

呼叫 unsubscribe() 會傳回承諾使用合約,因為系統可能需要一段時間才能完成作業。您聲明瞭這項承諾,因此鏈結中的下一個 then() 會等待 unsubscribe() 完成。您也可以新增擷取處理常式,以在發生錯誤時呼叫 unsubscribe() 結果。之後您就可以更新使用者介面。

.then(function() {
  updateSubscriptionOnServer(null);

  console.log('User is unsubscribed.');
  isSubscribed = false;

  updateBtn();
})

實戰演練

您應該能在網路應用程式中按下 [啟用推播訊息] 或 [停用推送訊息功能],該記錄會顯示已訂閱及取消訂閱的使用者。

恭喜您完成這個程式碼研究室!

本程式碼研究室說明瞭如何在網路應用程式中新增推播通知,協助您順利上手。如要進一步瞭解網路通知可執行的動作,請參閱這些文件

如果您想在網站上部署推播通知,建議您為採用舊版瀏覽器或採用 GCM 規定的標準瀏覽器新增支援。按這裡即可瞭解詳情

其他資訊

相關網誌文章