1. 總覽
推送訊息是一種簡單又有效的方法,可讓您與使用者再次互動。在本程式碼研究室中,您將瞭解如何在網頁應用程式中加入推播通知。
課程內容
- 如何為使用者訂閱及取消訂閱推送訊息
- 如何處理傳入的推送訊息
- 如何顯示通知
- 如何回應通知點擊
軟硬體需求
- Chrome 52 以上版本
- Chrome 版網路伺服器或您自選的網路伺服器
- 文字編輯器
- HTML、CSS、JavaScript 和 Chrome 開發人員工具的基本知識
- 程式碼範例 (請參閱「進行設定」)。
2. 做好準備
下載程式碼範例
您可以透過兩種方式取得本程式碼研究室的程式碼範例:
- 複製 Git 存放區:
git clone https://github.com/GoogleChrome/push-notifications.git
- 下載 ZIP 檔案:
如果將來源下載為 ZIP 檔案,解壓縮後就會取得根資料夾 push-notifications-master
。
安裝並驗證網路伺服器
雖然您自己的網路伺服器是免費的,但本程式碼研究室適合與 Chrome 版 Web 應用程式搭配使用。如果尚未安裝這個應用程式,可以前往 Chrome 線上應用程式商店下載:
安裝 Chrome 應用程式的網路伺服器後,請按一下書籤列上的「應用程式」捷徑:
在「應用程式」視窗中,按一下「網路伺服器」圖示:
您接下來會看到這個對話方塊,可讓您設定本機網路伺服器:
按一下「選取資料夾」按鈕,然後選取下載後 push-notifications
資料夾中的 app
資料夾。這樣一來,您就可以透過對話方塊的「網路伺服器網址」部分顯示的網址,提供處理中的工作。
在「Options」下方,勾選「自動顯示 index.html」旁的方塊,如下所示:
接著,將「Web Server: STARTED」(網路伺服器:STARTED) 切換按鈕往左側,再向右移回右側,藉此停止並重新啟動伺服器。
按一下網路伺服器網址,在網路瀏覽器中造訪您的網站。您應該會看到類似下方的頁面,不過您的版本網址可能會顯示 127.0.0.1:8887:
一律更新 Service Worker
在開發過程中,建議您確認服務工作處理程序使用的是最新版本並擁有最新變更。
如何在 Chrome 中設定這項功能:
- 前往「Push Codelab」分頁。
- 開啟開發人員工具:Windows 和 Linux 系統的 Ctrl-Shift-I 鍵;macOS 為 Cmd-Option-I 鍵。
- 選取「Application」面板,按一下「Service Workers」分頁標籤,然後勾選「Update on Reload」核取方塊。啟用這個核取方塊後,每次網頁重新載入時,Service Worker 就會強制更新。
3. 註冊 Service Worker
請注意,app
目錄中有一個名為 sw.js
的空白檔案。這個檔案會做為您的 Service Worker。但目前可以留空。稍後您要在其中加入程式碼。
首先,您必須將這個檔案註冊為 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';
}
這個程式碼會檢查您的瀏覽器是否支援 Service Worker 和推送訊息。如果支援這些程式碼,程式碼就會註冊您的 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>';
重要事項:切勿將私密金鑰放在網頁應用程式中!
4. 初始化狀態
目前網頁應用程式的「啟用」按鈕已停用,因此無法點選。這是因為建議您預設停用「推播」按鈕,等到確定瀏覽器支援推送訊息功能後,再啟用這個按鈕。這樣一來,您就能檢查使用者目前是否已訂閱訊息功能。
您必須在 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;
}
這個函式會啟用按鈕,並根據使用者是否訂閱變更按鈕文字。
最後,當 Service Worker 已在 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
。
在您完成本程式碼研究室的其餘步驟時,只要訂閱或取消訂閱,按鈕文字應該就會出現變化。
5. 訂閱使用者
目前 [啟用推送訊息] 按鈕功能沒什麼作用。讓我們一起解決這個問題!
在 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
的頂端。
轉換值之後,請在 Service Worker 的 pushManager
上呼叫 subscribe()
方法,傳入應用程式伺服器的公開金鑰和 userVisibleOnly: true
值。
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
})
userVisibleOnly
參數可確保每次傳送推送訊息時顯示通知。目前這是必填欄位,必須為 true。
呼叫 subscribe()
會傳回承諾,完成下列步驟後會解決:
- 使用者已授予顯示通知的權限。
- 瀏覽器已將網路要求傳送至推送服務,以取得產生
PushSubscription
所需的資料。
如果上述步驟成功,subscribe()
承諾將透過 PushSubscription
解決。如果使用者未授予權限,或是訂閱使用者時發生問題,保證會遭到拒絕並傳回錯誤。這可在程式碼研究室中為您提供以下承諾鏈:
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 資料形式查看訂閱項目。
6. 處理權限遭拒
如果使用者封鎖了權限要求,系統會發生尚未處理的情況。這需要特別考量,因為如果使用者封鎖權限,網頁應用程式就無法重新顯示權限提示,也無法訂閱該名使用者。您至少要停用「推送」按鈕,讓使用者知道該按鈕無法使用。
針對這種情況,最明顯的位置位於 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」,然後將「通知」權限變更為「使用全域預設值 (要求)」。
變更這項設定後,請重新整理頁面並按一下「啟用推送訊息」按鈕,然後在權限對話方塊中選取「封鎖」。這個按鈕將會停用,並顯示「Push Messaging Block」(推送訊息已封鎖) 文字。
透過這項變更,您現在可以為使用者訂閱,以處理可能的權限情境。
7. 處理推送事件
在瞭解如何從後端傳送推送訊息之前,需要先考量訂閱的使用者收到推送訊息時會發生什麼情況。
當您觸發推送訊息時,瀏覽器會收到推送訊息、判斷要推送的目標 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));
});
現在來逐步瞭解這個程式碼。您正在透過新增事件監聽器來監聽 Service Worker 中的 push
事件:
self.addEventListener('push', ... );
(除非您先前玩過 Web Worker,否則 self
可能不是最新版本。在 Service Worker 檔案中,self
參照 Service Worker 本身。
收到推送訊息時,系統會呼叫事件監聽器,而您可以在 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);
現在您已經完成推送事件,讓我們開始測試推送事件。
馬上試試
在 Service Worker 中,您可以透過推送事件處理功能觸發假推送事件,測試收到訊息時會發生什麼事。
在網頁應用程式中,訂閱推送訊息服務,並確認控制台中會顯示 User IS subscribed
。在開發人員工具的「Application」面板中,點選「Service Workers」分頁標籤下方的「Push」按鈕:
點選「推送」後,您應該會看到類似下方的通知:
注意:如果這個步驟無法解決問題,請嘗試使用開發人員工具應用程式面板中的 [取消註冊] 連結取消註冊 Service Worker,並等待 Service Worker 停止,再重新載入頁面。
8. 通知點擊
如果您點選其中一則通知,您會發現沒有任何變化。您可以監聽 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()
確保在顯示新視窗或分頁之前,瀏覽器不會終止 Service Worker。
馬上試試
請嘗試在開發人員工具中再次觸發推送訊息,然後按一下通知。這時通知會關閉,並且開啟新分頁。
9. 傳送推送訊息
您已經發現網頁應用程式可以使用開發人員工具顯示通知,並研究如何按一下滑鼠來關閉通知。下一步是傳送實際的推送訊息。
一般而言,使用者必須將訂閱項目從網頁傳送至後端。接著,後端會對訂閱項目中的端點發出 API 呼叫,藉此觸發推送訊息。
此內容不在本程式碼研究室的涵蓋範圍內,但您可以使用隨附網站 ( web-push-codelab.glitch.me) 觸發實際的推送訊息。將訂閱項目貼到頁面底部:
然後貼到 [Subscription to Send to] (訂閱對象) 文字區域的隨附網站中:
在「文字要傳送」下方,新增要隨推送訊息傳送的任何字串。
按一下 [傳送推送訊息] 按鈕。
你應該會收到推送訊息。您使用的文字會記錄在控制台中。
您應該可以藉此測試傳送和接收資料,並進而操控通知。
隨附應用程式只是節點伺服器,會使用網頁推送程式庫傳送訊息。建議您查看 GitHub 上的 web-push-libs 機構,瞭解有哪些程式庫可用於傳送推送訊息。這個動作會處理許多細節,觸發推送訊息。
您可以查看隨附網站的所有程式碼。
10. 取消訂閱使用者
還有一個好處是能夠取消訂閱使用者。為此,您必須在 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();
})
馬上試試
您應可以在網頁應用程式中按下 [啟用推送訊息功能] 或 [停用推送訊息],這樣就能在記錄中看到使用者已經訂閱和取消訂閱了。
11. 已完成
恭喜您完成本程式碼研究室!
本程式碼研究室已說明如何在網頁應用程式中新增推播通知,快速上手。如要進一步瞭解網頁通知的功能,請參閱這些文件。
如果您想在網站上部署推播通知,建議您支援舊版瀏覽器,或使用 GCM 的非標準瀏覽器更新。請按這裡瞭解詳情。