推送訊息是簡單又有效的方法,可讓使用者再次與您互動。在本程式碼研究室中,您將瞭解如何將推播通知新增至網路應用程式。
課程內容
- 如何訂閱及取消訂閱使用者的推播訊息
- 如何處理收到的推播訊息
- 如何顯示通知
- 如何回應通知點擊
軟硬體需求
- Chrome 52 以上版本
- Chrome 適用的網頁伺服器,或您選擇的網頁伺服器
- 文字編輯器
- 具備 HTML、CSS、JavaScript 和 Chrome 開發人員工具的基本知識
- 範例程式碼 (請參閱「開始設定」一節)
下載範例程式碼
您可以透過兩種方式取得本程式碼研究室的程式碼範例:
- 複製 Git 存放區:
git clone https://github.com/GoogleChrome/push-notifications.git
- 下載 ZIP 檔案:
如果將來源下載為 ZIP 檔案,解壓縮後會得到根資料夾 push-notifications-master。
安裝及驗證網路伺服器
您可以自由使用自己的網路伺服器,但本程式碼研究室的設計與 Chrome 專用的網路伺服器應用程式相容。如果尚未安裝該應用程式,請前往 Chrome 線上應用程式商店下載:
安裝 Web Server for Chrome 應用程式後,請按一下書籤列上的「應用程式」捷徑:

在「應用程式」視窗中,按一下「網頁伺服器」圖示:

接著會看到這個對話方塊,可供您設定本機網路伺服器:

按一下「選擇資料夾」按鈕,然後選取您下載的 push-notifications 資料夾中的 app 資料夾。這樣一來,您就能透過對話方塊「Web Server URL(s)」部分顯示的網址,提供正在進行的工作。
在「選項」下方,勾選「自動顯示 index.html」旁的方塊,如下所示:

接著將「Web Server: STARTED」切換鈕滑動至左側,然後再滑動至右側,停止並重新啟動伺服器。

按一下「Web Server URL」,即可在網路瀏覽器中造訪網站。您應該會看到類似下方的頁面,但您的版本可能會顯示 127.0.0.1:8887 做為地址:

務必更新 Service Worker
在開發期間,請務必確保 Service Worker 隨時保持在最新狀態,並採用最新變更。
如要在 Chrome 中設定這項功能,請按照下列步驟操作:
- 前往「Push Codelab」分頁。
- 開啟開發人員工具:在 Windows 和 Linux 上按 Ctrl-Shift-I,在 macOS 上按 Cmd-Option-I。
- 選取「應用程式」面板,按一下「服務工作人員」分頁,然後勾選「重新載入時更新」核取方塊。啟用這個核取方塊後,每次重新載入網頁時,系統都會強制更新 Service Worker。

在 app 目錄中,您會看到名為 sw.js 的空白檔案。這個檔案就是服務工作人員。目前可以留空。您稍後會加入程式碼。
首先,您需要將這個檔案註冊為服務工作人員。
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
您可以在這裡產生公開和私密金鑰組。

將公開金鑰複製到 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() 會傳回 Promise,如果目前有訂閱項目,就會使用該項目解析 Promise。否則會傳回 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」(推播程式碼研究室) 分頁。您應該會看到「啟用即時訊息」按鈕現在已啟用 (可以點選),且主控台中會顯示 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 網址安全編碼),並轉換為 UInt8Array,因為這是 subscribe() 呼叫的預期輸入內容。urlB64ToUint8Array() 函式位於 scripts/main.js 的頂端。
轉換值後,請在服務工作人員的 pushManager 上呼叫 subscribe() 方法,並傳入應用程式伺服器的公開金鑰和值 userVisibleOnly: true。
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
})userVisibleOnly 參數可確保每次傳送推播訊息時,系統都會顯示通知。目前必須提供這個值,且必須為 true。
呼叫 subscribe() 會傳回 Promise,在完成下列步驟後會解析:
- 使用者已授予顯示通知的權限。
- 瀏覽器已向推送服務發出網路要求,以取得產生
PushSubscription所需的資料。
如果這些步驟成功,subscribe() promise 會以 PushSubscription 解決。如果使用者未授予權限,或訂閱使用者時發生任何問題,承諾就會因錯誤而遭到拒絕。這會在程式碼研究室中提供下列 Promise 鏈結:
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,然後將「通知」權限變更為「使用全域預設值 (詢問)」。

變更這項設定後,請重新整理頁面,然後按一下「啟用推播訊息」按鈕,並在權限對話方塊中選取「封鎖」。按鈕會停用,並顯示「已封鎖推播訊息」文字。

完成這項變更後,您現在可以訂閱使用者,並處理可能的權限情境。
瞭解如何從後端傳送推播訊息前,請先考量訂閱使用者收到推播訊息時的實際情況。
觸發推播訊息時,瀏覽器會收到推播訊息,找出推播訊息適用的 Service Worker,喚醒該 Service Worker,然後分派推播事件。您需要監聽這個事件,並顯示通知。
在 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 Worker,否則 self 可能是新功能。在服務工作人員檔案中,self 參照服務工作人員本身。)
收到推播訊息時,系統會呼叫事件監聽器,而您則可呼叫服務工作人員的 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()。這個方法會採用 Promise,讓瀏覽器保持服務工作站的運作狀態,直到傳入的 Promise 已解決為止。
為了方便理解上述程式碼,您可以重新編寫如下:
const notificationPromise = self.registration.showNotification(title, options);
event.waitUntil(notificationPromise);現在您已逐步瞭解推送事件,接下來請測試推送事件。
馬上試試
在 Service Worker 中處理推送事件時,您可以觸發假的推送事件,測試收到訊息時會發生什麼情況。
在網頁應用程式中訂閱推播訊息,並確認控制台中顯示 User IS subscribed。在開發人員工具的「應用程式」面板中,按一下「服務工作人員」分頁下方的「推送」按鈕:

按一下「推送」後,您應該會看到類似以下的通知:

注意:如果這個步驟無效,請嘗試使用開發人員工具「應用程式」面板中的「取消註冊」連結取消註冊 Service Worker,等待 Service Worker 停止運作,然後重新載入頁面。
如果您點選其中一則通知,會發現沒有任何反應。您可以在 Service Worker 中監聽 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) 觸發實際的推播訊息。將訂閱項目貼到頁面底部:

然後將這段文字貼到隨附網站的「Subscription to Send To」(要傳送至的訂閱項目) 文字區域:

在「要傳送的文字」下方,新增要隨推播訊息傳送的任何字串。
按一下「傳送推播訊息」按鈕。

接著,您應該會收到推送訊息。您使用的文字會記錄到控制台。

您應該有機會測試傳送及接收資料,並據此操控通知。
隨附應用程式只是使用 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 解析的 Promise;否則會傳回 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() 會傳回 Promise,因為完成作業可能需要一些時間。您會傳回該 Promise,因此鏈結中的下一個 then() 會等待 unsubscribe() 完成。您也可以新增 catch 處理常式,以防呼叫 unsubscribe() 時發生錯誤。完成後,您就可以更新 UI。
.then(function() {
updateSubscriptionOnServer(null);
console.log('User is unsubscribed.');
isSubscribed = false;
updateBtn();
})馬上試試
您應該可以在網頁應用程式中按下「啟用推播訊息」或「停用推播訊息」,記錄檔會顯示使用者訂閱及取消訂閱的狀態。

恭喜您完成本程式碼研究室!
本程式碼研究室已說明如何開始在網頁應用程式中新增推播通知。如要進一步瞭解網頁通知的功能,請參閱這些文件。
如要在網站上部署推播通知,您可能會想新增對舊版瀏覽器或使用 GCM 的非標準相容瀏覽器的支援。請按這裡瞭解詳情。