開放網路上的推播通知

Matt Gaunt

如果您詢問開發人員的行動裝置功能需要哪些行動裝置功能,那麼推播通知永遠會顯示在清單中。

推播通知可讓使用者選擇接收喜愛網站即時更新的消息,並讓您透過自訂的引人入勝內容,有效地再次與他們互動。

自 Chrome 42 版起,開發人員可使用 Push APINotification API

Chrome 中的 Push API 採用幾項技術,包括網頁應用程式資訊清單Service Worker。在本文中,我們將介紹這些技術,但只有最少的就是能讓訊息順利上線運作的必備條件。請查看上方連結,進一步瞭解資訊清單的其他功能,以及服務工作處理程序的離線功能。

我們也會瞭解日後的 Chrome 版本會加入哪些 API,再來介紹一些常見問題。

實作 Chrome 的推送訊息

本節說明在網頁應用程式中支援推送訊息時,必須完成的每個步驟。

註冊 Service Worker

要求 Service Worker 必須實作網路推送訊息。原因在於,瀏覽器在收到推送訊息後,可以啟動一個服務工作站。服務工作站會在背景不開啟頁面的情況下執行,並分派事件,方便您決定該如何處理該推送訊息。

以下範例說明如何在網頁應用程式中註冊 Service Worker。註冊成功後,我們就會呼叫 initialiseState(),我們稍後會說明。

var isPushEnabled = false;

…

window.addEventListener('load', function() {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.addEventListener('click', function() {
    if (isPushEnabled) {
        unsubscribe();
    } else {
        subscribe();
    }
    });

    // Check that service workers are supported, if so, progressively
    // enhance and add push messaging support, otherwise continue without it.
    if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js')
    .then(initialiseState);
    } else {
    console.warn('Service workers aren\'t supported in this browser.');
    }
});

按鈕點擊處理常式會訂閱或取消訂閱使用者推送訊息。isPushEnabled 是全域變數,只會追蹤目前是否訂閱推送訊息。系統會在整段程式碼片段中參照這些屬性。

接著,我們會先確認系統是否支援 Service Worker,然後再註冊具有處理推送訊息邏輯的 service-worker.js 檔案。這裡我們只是告訴瀏覽器,這個 JavaScript 檔案是本網站的 Service Worker。

設定初始狀態

Chrome 已啟用及停用的推送訊息使用者體驗範例。

服務工作處理程序註冊完成後,就需要設定 UI 的狀態。

使用者會預期有一個簡單的 UI,可啟用或停用網站的推送訊息,並預期使用者會預期看到任何變更。換句話說,如果他們為網站啟用推送訊息、離開,並在一週後回來,使用者介面應醒目顯示該訊息已經啟用。

您可以參考本文件中的使用者體驗指南,我們將著重探討技術層面。

您目前可能只認為只有兩個狀態可以處理、已啟用或停用。不過,有些通知狀態有必要考量這一點。

這張圖表醒目顯示在 Chrome 中推送的不同註意事項和狀態

我們必須先檢查一些 API,才能啟用按鈕。如果全都支援,可以啟用 UI 並設定初始狀態,指出是否訂閱推送訊息。

由於大部分檢查都會停用使用者介面,因此您應將初始狀態設為停用。這樣也能避免網頁的 JavaScript 發生問題時造成混淆,例如無法下載 JS 檔案,或使用者已停用 JavaScript。

<button class="js-push-button" disabled>
    Enable Push Messages
</button>

藉由這個初始狀態,我們可以執行 initialiseState() 方法中所列的檢查,即註冊 Service Worker 後。

// Once the service worker is registered set the initial state
function initialiseState() {
    // Are Notifications supported in the service worker?
    if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
    console.warn('Notifications aren\'t supported.');
    return;
    }

    // Check the current Notification permission.
    // If its denied, it's a permanent block until the
    // user changes the permission
    if (Notification.permission === 'denied') {
    console.warn('The user has blocked notifications.');
    return;
    }

    // Check if push messaging is supported
    if (!('PushManager' in window)) {
    console.warn('Push messaging isn\'t supported.');
    return;
    }

    // We need the service worker registration to check for a subscription
    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // Do we already have a push message subscription?
    serviceWorkerRegistration.pushManager.getSubscription()
        .then(function(subscription) {
        // Enable any UI which subscribes / unsubscribes from
        // push messages.
        var pushButton = document.querySelector('.js-push-button');
        pushButton.disabled = false;

        if (!subscription) {
            // We aren't subscribed to push, so set UI
            // to allow the user to enable push
            return;
        }

        // Keep your server in sync with the latest subscriptionId
        sendSubscriptionToServer(subscription);

        // Set your UI to show they have subscribed for
        // push messages
        pushButton.textContent = 'Disable Push Messages';
        isPushEnabled = true;
        })
        .catch(function(err) {
        console.warn('Error during getSubscription()', err);
        });
    });
}

這些步驟的簡要總覽:

  • 我們會檢查 ServiceWorkerRegistration 原型是否提供 showNotification。如未這麼做,服務工作站在收到推送訊息時就無法顯示通知。
  • 我們會檢查目前的 Notification.permission 是否為 "denied",權限遭拒表示除非使用者在瀏覽器中手動變更權限,否則您無法顯示通知。
  • 如要檢查是否支援推送訊息,我們會檢查視窗物件是否提供 PushManager
  • 最後,我們使用 pushManager.getSubscription() 檢查我們是否已有訂閱。此時,我們會將訂閱詳細資料傳送到伺服器,確保取得正確的資訊,並設定使用者介面,指出推送訊息功能是否已啟用。本文稍後會說明訂閱物件中有哪些詳細資料。

我們會等到 navigator.serviceWorker.ready 解析完畢以檢查訂閱項目並啟用推送按鈕,因為此動作只有在服務工作站啟用後,才能實際訂閱推送訊息。

下一步是處理使用者想啟用推送訊息的時機,但必須先設定 Google Developer Console 專案,並在資訊清單中加入一些參數,才能使用 Firebase 雲端通訊 (FCM) (舊稱 Google 雲端通訊 (GCM)。

在 Firebase Developer Console 建立專案

Chrome 會使用 FCM 處理推送訊息的傳送和傳送,但您需要在 Firebase Developer Console 中設定專案,才能使用 FCM API。

下列步驟僅適用於他們使用 FCM 的 Chrome、Android 版 Opera 和 Samsung 瀏覽器。本文稍後的章節會說明這項功能在其他瀏覽器中的運作原理。

建立新的 Firebase 開發人員專案

首先,您必須在 https://console.firebase.google.com/ 上按一下「建立新專案」建立新專案。

新增 Firebase 專案的螢幕截圖

新增專案名稱、建立專案,系統會將您帶往專案資訊主頁:

Firebase 專案首頁

在這個資訊主頁中,按一下左上角的專案名稱旁的齒輪圖示,然後按一下「Project Settings」(專案設定)。

Firebase 專案設定選單

在設定頁面中,按一下 [雲端通訊] 標籤。

Firebase 專案雲端通訊選單

本頁包含推送訊息的 API 金鑰,稍後會用到這個金鑰,以及下一節需要放入網頁應用程式資訊清單的傳送者 ID。

新增網頁應用程式資訊清單

針對推送作業,我們需要新增含 gcm_sender_id 欄位的資訊清單檔案,推送訂閱項目成功。只有 Chrome、Android 和 Samsung 瀏覽器需要 Opera 才需要使用這個參數,因此可以使用 FCM / GCM。

這些瀏覽器透過 FCM 訂閱使用者的裝置時,會使用 gcm_sender_id。也就是說,FCM 可識別使用者的裝置,並確認傳送者 ID 與對應的 API 金鑰相符,且使用者已允許您的伺服器向使用者傳送推送訊息。

以下是超簡單的資訊清單檔案:

{
    "name": "Push Demo",
    "short_name": "Push Demo",
    "icons": [{
        "src": "images/icon-192x192.png",
        "sizes": "192x192",
        "type": "image/png"
        }],
    "start_url": "/index.html?homescreen=1",
    "display": "standalone",
    "gcm_sender_id": "<Your Sender ID Here>"
}

您必須將 gcm_sender_id 值設為 Firebase 專案中的傳送者 ID。

將資訊清單檔案儲存在專案 (manifest.json 是不錯的名稱) 後,請在頁面標題中,透過下列標記在 HTML 中參照該檔案。

<link rel="manifest" href="/manifest.json">

如果您未使用這些參數新增網路資訊清單,當您嘗試訂閱使用者推送訊息時,會收到例外狀況,並顯示 "Registration failed - no sender id provided""Registration failed - permission denied" 錯誤。

訂閱推送訊息

資訊清單設定完成後,您可以返回網站的 JavaScript。

如要訂閱,您必須在 PushManager 物件上呼叫 subscribe() 方法,即可透過 ServiceWorkerRegistration 存取。

這會要求使用者授予來源權限,以便傳送推播通知。如果沒有這項權限,就無法成功訂閱。

如果 subscribe() 方法傳回的 promise 可以解析,您會收到 PushSubscription 物件,其中包含 端點

您應將每位使用者的端點儲存在伺服器中,因為之後使用者可用來傳送推送訊息。

以下程式碼會訂閱推送訊息的使用者:

function subscribe() {
    // Disable the button so it can't be changed while
    // we process the permission request
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;

    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    serviceWorkerRegistration.pushManager.subscribe()
        .then(function(subscription) {
        // The subscription was successful
        isPushEnabled = true;
        pushButton.textContent = 'Disable Push Messages';
        pushButton.disabled = false;

        // TODO: Send the subscription.endpoint to your server
        // and save it to send a push message at a later date
        return sendSubscriptionToServer(subscription);
        })
        .catch(function(e) {
        if (Notification.permission === 'denied') {
            // The user denied the notification permission which
            // means we failed to subscribe and the user will need
            // to manually change the notification permission to
            // subscribe to push messages
            console.warn('Permission for Notifications was denied');
            pushButton.disabled = true;
        } else {
            // A problem occurred with the subscription; common reasons
            // include network errors, and lacking gcm_sender_id and/or
            // gcm_user_visible_only in the manifest.
            console.error('Unable to subscribe to push.', e);
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
        }
        });
    });
}

此時,您的網頁應用程式已準備好接收推送訊息,但在我們將推送事件監聽器新增至 Service Worker 檔案前不會執行任何動作。

Service Worker 推送事件監聽器

收到推送訊息時 (我們會在下一節說明如何傳送推送訊息),服務工作站會分派推送事件,而在這個情況下,您需要顯示通知

self.addEventListener('push', function(event) {
    console.log('Received a push message', event);

    var title = 'Yay a message.';
    var body = 'We have received a push message.';
    var icon = '/images/icon-192x192.png';
    var tag = 'simple-push-demo-notification-tag';

    event.waitUntil(
    self.registration.showNotification(title, {
        body: body,
        icon: icon,
        tag: tag
    })
    );
});

此程式碼會註冊推送事件監聽器,並顯示含有預先定義標題、內文、圖示和通知標記的通知。這個範例需要特別留意的一項細微差異是 event.waitUntil() 方法。這個方法會接收 promise 並延長事件處理常式的生命週期 (或可視為維持服務 worker 的生命週期),直到承諾達成為止;在這種情況下,傳遞至 event.waitUntil 的承諾就是來自 showNotification() 的傳回承諾。

通知標記是專屬通知的 ID。如果我們將兩則推送訊息傳送至同一個端點,兩者之間短暫延遲,並且顯示相同標記的通知,則瀏覽器會在收到推送訊息時顯示第一則通知,並以第二則通知取代。

如要一次顯示多則通知,請改用其他標記,或是完全不標記。我們會深入示範如何在本文的後續部分顯示通知。現在,我們先簡單說明,看看傳送推送訊息是否會顯示這則通知。

傳送推送訊息

我們訂閱了推送訊息,Service Worker 也準備好顯示通知,準備透過 FCM 傳送推送訊息了。

這僅適用於使用 FCM 的瀏覽器。

當您將 PushSubscription.endpoint 變數傳送至伺服器時,FCM 的端點是特殊的。網址結尾有一個參數,也就是 registration_id

端點範例如下:

https://fcm.googleapis.com/fcm/send/APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

FCM 網址為:

https://fcm.googleapis.com/fcm/send

registration_id 會是:

APA91bHPffi8zclbIBDcToXN_LEpT6iA87pgR-J-MuuVVycM0SmptG-rXdCPKTM5pvKiHk2Ts-ukL1KV8exGOnurOAKdbvH9jcvg8h2gSi-zZJyToiiydjAJW6Fa9mE3_7vsNIgzF28KGspVmLUpMgYLBd1rxaVh-L4NDzD7HyTkhFOfwWiyVdKh__rEt15W9n2o6cZ8nxrP

這項錯誤僅適用於使用 FCM 的瀏覽器。在一般瀏覽器中,您只要取得端點,並以標準方式呼叫該端點,且無論網址為何,端點都能正常運作。

也就是說,您需要在伺服器上檢查端點是否適用於 FCM,如果是 FCM,請擷取 registration_id。如要在 Python 中執行此操作,您可以執行類似以下的操作:

if endpoint.startswith('https://fcm.googleapis.com/fcm/send'):
    endpointParts = endpoint.split('/')
    registrationId = endpointParts[len(endpointParts) - 1]

    endpoint = 'https://fcm.googleapis.com/fcm/send'

取得註冊 ID 後,即可呼叫 FCM API。您可以按這裡查看 FCM API 的參考文件。

呼叫 FCM 時,請注意以下重點:

  • 呼叫 API 時,您必須設定 key=&lt;YOUR_API_KEY&gt;Authorization 標頭,其中 &lt;YOUR_API_KEY&gt; 是 Firebase 專案的 API 金鑰。
    • FCM 會使用 API 金鑰尋找適當的傳送者 ID,確保使用者已授予專案權限,最後確認伺服器的 IP 位址已加入許可清單。
  • application/jsonapplication/x-www-form-urlencoded;charset=UTF-8 的適當 Content-Type 標頭,取決於您將資料傳送為 JSON 或表單資料而定。
  • registration_ids 的陣列:您要從使用者端點擷取的註冊 ID。

請參閱說明文件,瞭解如何從伺服器傳送推送訊息。不過,如要快速檢查服務工作站,可以使用 cURL 將推送訊息傳送至瀏覽器。

將這個 cURL 指令中的 &lt;YOUR_API_KEY&gt;&lt;YOUR_REGISTRATION_ID&gt; 替換為您自己的值,然後在終端機中執行。

您應該會看到灰色的通知:

    curl --header "Authorization: key=<YOUR_API_KEY>" --header
    "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d
    "{\"registration_ids\":[\"<YOUR_REGISTRATION_ID>\"]}"
Chrome for Android 的推送訊息範例。

開發後端邏輯時,請記得 POST 主體的授權標頭和格式只適用於 FCM 端點,因此可偵測端點是否適用於 FCM,並有條件地新增標頭和設定 POST 主體格式。如果您使用其他瀏覽器 (未來可能希望 Chrome 這麼做),則需要實作網路推送通訊協定

除了目前在 Chrome 中導入 Push API 的缺點之外,您也無法透過推送訊息傳送任何資料。不會。這是因為在日後的實作中,酬載資料必須先在您的伺服器上加密,然後才會傳送至推送訊息端點。如此一來,端點無論其為何,都無法輕鬆查看推送訊息的內容。還能防範其他安全漏洞,例如 HTTPS 憑證驗證不佳,以及伺服器與推送供應商之間的中間人攻擊。不過,系統尚未支援這種加密機制,因此您目前必須執行擷取作業,取得填入通知所需的資訊。

更完整的推送事件範例

目前為止,我們看到的通知都非常基本,而且就所有範例而言,都不太能涵蓋實際使用情境。

實際上,大部分使用者都希望在顯示通知之前,從伺服器取得部分資訊。這類資料可以是為通知標題和訊息填入特定資訊,也可以再進一步快取部分頁面或資料,這樣一來,只要使用者點選通知,就能在瀏覽器開啟時立即取得所有內容,即使當時無法使用網路也不例外。

在下列程式碼中,我們從 API 擷取部分資料、將回應轉換為物件,並用來填入通知。

self.addEventListener('push', function(event) {
    // Since there is no payload data with the first version
    // of push messages, we'll grab some data from
    // an API and use it to populate a notification
    event.waitUntil(
    fetch(SOME_API_ENDPOINT).then(function(response) {
        if (response.status !== 200) {
        // Either show a message to the user explaining the error
        // or enter a generic message and handle the
        // onnotificationclick event to direct the user to a web page
        console.log('Looks like there was a problem. Status Code: ' + response.status);
        throw new Error();
        }

        // Examine the text in the response
        return response.json().then(function(data) {
        if (data.error || !data.notification) {
            console.error('The API returned an error.', data.error);
            throw new Error();
        }

        var title = data.notification.title;
        var message = data.notification.message;
        var icon = data.notification.icon;
        var notificationTag = data.notification.tag;

        return self.registration.showNotification(title, {
            body: message,
            icon: icon,
            tag: notificationTag
        });
        });
    }).catch(function(err) {
        console.error('Unable to retrieve data', err);

        var title = 'An error occurred';
        var message = 'We were unable to get the information for this push message';
        var icon = URL_TO_DEFAULT_ICON;
        var notificationTag = 'notification-error';
        return self.registration.showNotification(title, {
            body: message,
            icon: icon,
            tag: notificationTag
        });
    })
    );
});

值得一提的是,event.waitUntil() 會接受導致 showNotification() 傳回的承諾,也就是在非同步 fetch() 呼叫完成且顯示通知之前,事件監聽器不會結束。

即使發生錯誤,系統仍會顯示通知,因為如果沒有,Chrome 會顯示自己的一般通知。

使用者點選通知時開啟網址

當使用者點選通知時,系統會在您的服務工作站中分派 notificationclick 事件。您可在處理常式中採取適當動作,例如聚焦於分頁,或開啟含有特定網址的視窗:

self.addEventListener('notificationclick', function(event) {
    console.log('On notification click: ', event.notification.tag);
    // Android doesn't close the notification when you click on it
    // See: http://crbug.com/463146
    event.notification.close();

    // This looks to see if the current is already open and
    // focuses if it is
    event.waitUntil(
    clients.matchAll({
        type: "window"
    })
    .then(function(clientList) {
        for (var i = 0; i < clientList.length; i++) {
        var client = clientList[i];
        if (client.url == '/' && 'focus' in client)
            return client.focus();
        }
        if (clients.openWindow) {
        return clients.openWindow('/');
        }
    })
    );
});

這個範例會將現有的相同來源分頁 (如有) 聚焦於現有的相同來源分頁,然後另外開啟新的來源分頁,將瀏覽器開啟網站來源的根目錄。

我們有一篇文章專門介紹可以使用 Notification API 進行的部分

取消訂閱使用者的裝置

您訂閱了使用者的裝置,對方也收到推送訊息,但該如何取消訂閱?

取消訂閱使用者裝置的主要必要步驟是呼叫 PushSubscription 物件上的 unsubscribe() 方法,並從伺服器中移除端點 (這樣即可避免傳送已知的推送訊息)。下方程式碼顧名思義:

function unsubscribe() {
    var pushButton = document.querySelector('.js-push-button');
    pushButton.disabled = true;

    navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
    // To unsubscribe from push messaging, you need get the
    // subscription object, which you can call unsubscribe() on.
    serviceWorkerRegistration.pushManager.getSubscription().then(
        function(pushSubscription) {
        // Check we have a subscription to unsubscribe
        if (!pushSubscription) {
            // No subscription object, so set the state
            // to allow the user to subscribe to push
            isPushEnabled = false;
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
            return;
        }

        var subscriptionId = pushSubscription.subscriptionId;
        // TODO: Make a request to your server to remove
        // the subscriptionId from your data store so you
        // don't attempt to send them push messages anymore

        // We have a subscription, so call unsubscribe on it
        pushSubscription.unsubscribe().then(function(successful) {
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
            isPushEnabled = false;
        }).catch(function(e) {
            // We failed to unsubscribe, this can lead to
            // an unusual state, so may be best to remove
            // the users data from your data store and
            // inform the user that you have done so

            console.log('Unsubscription error: ', e);
            pushButton.disabled = false;
            pushButton.textContent = 'Enable Push Messages';
        });
        }).catch(function(e) {
        console.error('Error thrown while unsubscribing from push messaging.', e);
        });
    });
}

讓訂閱保持在最新狀態

FCM 和你的伺服器之間的訂閱項目可能不一致。請確保您的伺服器會剖析 FCM API 的傳送 POST 的回應主體,尋找 error:NotRegisteredcanonical_id 結果,詳情請參閱 FCM 說明文件

服務工作站和伺服器之間也可能無法同步訂閱。舉例來說,成功訂閱/取消訂閱後,不穩定的網路連線可能會導致您無法更新伺服器;或者使用者可能會撤銷通知權限,導致自動取消訂閱。請定期檢查 serviceWorkerRegistration.pushManager.getSubscription() 的結果 (例如在網頁載入時) 並將結果與伺服器同步,以便處理這類情況。如果您已沒有訂閱項目,且 Notification.permission ==「granted」,您也可以自動重新訂閱。

sendSubscriptionToServer() 中,更新 endpoint 時,您必須思考要如何處理失敗的網路要求。其中一個解決方法是利用 Cookie 追蹤 endpoint 的狀態,判斷伺服器是否需要最新的詳細資料。

以上所有步驟都會在 Chrome 46 中完整實作在網路上推送訊息的功能。仍有規格功能有助於簡化相關作業 (例如觸發推送訊息的標準 API),但這個版本可讓您立即開始將推送訊息功能建構到網頁應用程式中。

如何對網頁應用程式進行偵錯

實作推送訊息時,錯誤會在其中一個位置或您的服務工作站出現。

您可以使用DevTools對網頁中的錯誤進行偵錯。如要對 Service Worker 問題進行偵錯,可以透過兩種方法:

  1. 依序前往 chrome://inspect >「Service worker」。這個檢視畫面並不會提供目前執行中的服務工作站以外的資訊。
  2. 前往 chrome://serviceworker-internals,即可查看 Service Worker 的狀態,並查看錯誤 (如果有的話)。在開發人員工具集有類似的功能組合之前,此為暫時性更新。

我們建議新手使用「開啟開發人員工具」核取方塊,並在服務工作站啟動時暫停執行 JavaScript,以便進行偵錯,是我提供給服務工作站新手的最佳做法之一。這個核取方塊會在服務工作站開始時新增中斷點和「暫停執行」,可讓您繼續或逐步執行 Service Worker 指令碼,並查看是否遇到任何問題。

這張螢幕截圖顯示暫停執行核取方塊位於 serviceworker-internals 的位置。

如果 FCM 和 Service Worker 的推送事件之間似乎發生問題,表示您無法查看 Chrome 是否收到任何內容,因此無法進行偵錯。關鍵在於確保伺服器發出 API 呼叫時,FCM 回應成功。如下所示:

{"multicast_id":1234567890,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1234567890"}]}

請留意 "success": 1 回應。如果您看到失敗,則表示該 FCM 註冊 ID 有誤,導致推送訊息無法傳送至 Chrome。

在 Android 版 Chrome 上對 Service Worker 進行偵錯

目前在 Android 版 Chrome 中對 Service Worker 進行偵錯並不容易。 您必須前往 chrome://inspect 並找到該裝置,並尋找名稱為「Worker pid:....」的清單項目,其中包含您的 Service Worker 網址。

螢幕截圖,顯示服務工作處理程序在 Chrome 檢查中的位置

推播通知的使用者體驗

Chrome 團隊已彙整一份文件,說明推播通知使用者體驗的最佳做法,以及一份文件,說明使用推播通知時的某些極端情況。

Chrome 和開放網路推送訊息功能的未來趨勢

本節將針對這項實作作業中的部分 Chrome 專屬部分,進行說明,以及與其他瀏覽器實作有何不同。

網路推播通訊協定和端點

Push API 標準的優點是,您應該能夠採用端點,將其傳送至您的伺服器,並透過實作網路推送通訊協定傳送推送訊息。

網路推送通訊協定是可讓推送供應商實作的新標準,讓開發人員不必擔心推送供應商是誰。這麼做可避免要求 API 金鑰及傳送特殊格式的資料,就像您與 FCM 一樣。

Chrome 是第一個導入 Push API 的瀏覽器,且 FCM 不支援網路推送通訊協定,因此 Chrome 需要使用 gcm_sender_id,因此您必須使用 FCM 適用的備用 API。

Chrome 最終目標是搭配 Chrome 和 FCM 使用網路推送通訊協定。

在那之前,您必須偵測端點「https://fcm.googleapis.com/fcm/send」,並與其他端點分開處理,例如以特定方式設定酬載資料的格式,並新增授權金鑰。

如何實作網路推送通訊協定?

Firefox Nightly 目前正在推動推送作業,應該是第一個實作網路推播通訊協定的瀏覽器。

常見問題

規格顯示在哪裡?

https://slightlyoff.github.io/ServiceWorker/spec/service_worker/ https://w3c.github.io/push-api/ https://notifications.spec.whatwg.org/

如果我的網站有多個來源,或是同時擁有網站和原生身分,我可以避免重複通知嗎?

目前還沒有解決方法,但你可以前往 Chromium 追蹤進度。

最理想的情境是為使用者裝置設定某種 ID,然後在伺服器端比對原生應用程式和網頁應用程式的訂閱 ID,並決定要將推送訊息傳送至哪個 ID。您可以透過螢幕大小、裝置型號,在網頁應用程式和原生應用程式之間共用產生的金鑰,但每個方法各有優缺點。

為什麼需要 gcm_sender_id?

Chrome、Android 版 Opera 和 Samsung 瀏覽器才需使用 Firebase Cloud Messaging (FCM) API。目標是在標準確定後,再使用 FCM 支援網路推送通訊協定。

為何不使用網路通訊端或伺服器傳送事件 (EventSource)?

使用推送訊息的優點是,即使頁面處於關閉狀態,系統仍會喚醒您的服務工作人員並顯示通知。Web Socket 和 EventSource 會在網頁或瀏覽器關閉時關閉連線。

如果我不需要背景事件傳送,該怎麼辦?

如果您不需要背景傳送,使用 Web Socket 就是絕佳選擇。

何時該在不顯示通知的情況下使用推送功能 (例如無聲背景推送)?

目前還沒有時間表的推出時程,但已有實作背景同步的意圖,在系統尚未決定或無法指定時,我們也將探討啟用無聲推送功能使用背景同步的流程。

為什麼需要 HTTPS?如何在開發期間解決這個問題?

Service Worker 需要安全來源,確保 Service Worker 指令碼來自預期的來源,且並非來自中間人攻擊。目前這表示實際網站使用 HTTPS,但 localhost 仍能正常運作。

瀏覽器支援的外觀為何?

Chrome 推出穩定版,Mozilla 的 Mozilla 也已正式在 Firefox Nightly 中推出。 詳情請參閱「實作 Push API」錯誤,並按這裡追蹤其通知的實作方式。

我可以在一段時間後移除通知嗎?

目前不行,但我們計劃新增支援功能,以便取得目前顯示的通知清單。如果您設有用途,為在顯示後設定通知的到期時間,我們希望能瞭解這是什麼,因此請新增留言,並將通知轉回 Chrome 團隊。

如果您只需要在特定期間後停止傳送推播通知給使用者,而且不關心通知保持顯示的時間長度,則可使用 FCM 的存留時間 (ttl) 參數,請按這裡瞭解詳情。

Chrome 的推送訊息功能有哪些限制?

本文概述了幾個限制:

  • Chrome 將 CCM 當做推送服務使用,會建立許多專屬需求。我們正在與你一起合作,看看其中有些解決方案在未來可以提升。
  • 您必須在收到推送訊息時顯示通知。
  • 電腦版 Chrome 會提醒,如果 Chrome 未執行,就無法接收推送訊息。這與一律會接收推送訊息的 ChromeOS 和 Android 不同。

是否不應該使用 Permissions API?

Chrome 已導入 Permission API,但不一定適用於所有瀏覽器。進一步瞭解詳情

為什麼我點選通知時,Chrome 沒有開啟先前的分頁?

這個問題只會影響目前未由服務工作站控制的網頁。您可以參閱這個網頁來瞭解詳情。

如果在使用者裝置收到推送通知時,通知已過期,該怎麼辦?

收到推送訊息時,您必須一律顯示通知。如果您要傳送通知,但只在特定一段時間內才有用,可以在 CCM 上使用「time_to_live」參數,這樣 FCM 就會在到期時不會傳送推送訊息。

詳情請參閱這裡

如果我傳送 10 則推送訊息,但只想讓裝置接收訊息,會發生什麼情況?

FCM 有「收合」參數,可用來指示 FCM 將相同「收合鍵」的任何待處理訊息替換為新訊息。

詳情請參閱這裡