開放網路上的推播通知

Matt Gaunt

如果您向一群開發人員詢問網頁缺少哪些行動裝置功能,推播通知一定會是首要考量。

使用者可以選擇訂閱喜愛的網站發布的最新消息,您也可以透過推播通知,以吸引人的自訂內容有效地與他們互動。

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

Chrome 中的 Push API 仰賴幾項不同的技術,包括網頁應用程式資訊清單服務工作者。在本文中,我們將探討這些技術,但只會說明啟用推播訊息所需的最低要求。如要進一步瞭解資訊清單的其他功能和服務工作程的離線功能,請查看上述連結。

我們也會討論日後 Chrome 版本將新增至 API 的內容,最後會提供常見問題。

實作 Chrome 推送訊息

本節將說明您必須完成的每個步驟,以便在網路應用程式中支援推播訊息。

註冊 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.js 檔案。這裡我們只是告訴瀏覽器,這個 JavaScript 檔案是網站的服務工作者。

設定初始狀態

範例:Chrome 中啟用和停用的推播訊息使用者體驗。

註冊服務工作者後,我們需要設定 UI 狀態。

使用者會期待簡單的使用者介面,可用來啟用或停用網站的推播訊息,並且會期待該介面能隨時更新任何變更。換句話說,如果使用者為您的網站啟用推播訊息,離開網站後一週後再回來,使用者介面應會醒目顯示已啟用推播訊息。

您可以參閱這份文件中的使用者體驗指南,本文將著重於技術層面。

您可能會認為只有兩種狀態需要處理,即啟用或停用。不過,您也需要考量通知的其他狀態。

圖表強調 Chrome 中推送的不同考量因素和狀態

啟用按鈕前,我們需要檢查多個 API,如果所有 API 都支援,我們就可以啟用 UI,並設定初始狀態,指出是否已訂閱推播訊息。

由於大多數的檢查會導致 UI 停用,因此您應將初始狀態設為停用。這樣一來,如果網頁的 JavaScript 發生問題 (例如無法下載 JS 檔案或使用者停用 JavaScript),就不會造成任何混淆。

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

有了這個初始狀態,我們就可以在 initialiseState() 方法中執行上述檢查,也就是在服務工作者註冊後。

// 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);
        });
    });
}

以下簡要說明這些步驟:

  • 我們會檢查 showNotification 是否可在 ServiceWorkerRegistration 原型中使用。否則,我們就無法在收到推播訊息時顯示服務工作者的通知。
  • 我們會檢查目前的 Notification.permission,確保其不是 "denied"。如果權限遭到拒絕,您就無法顯示通知,除非使用者在瀏覽器中手動變更權限。
  • 如要確認是否支援推播訊息,我們會檢查 PushManager 是否可在視窗物件中使用。
  • 最後,我們使用 pushManager.getSubscription() 檢查是否已訂閱。如果是,我們會將訂閱詳細資料傳送至伺服器,確保我們擁有正確的資訊,並設定 UI 指出是否已啟用推播訊息。我們會在本文稍後的部分,說明訂閱物件中包含哪些詳細資料。

我們會等待 navigator.serviceWorker.ready 解析完成,再檢查訂閱項目並啟用推送按鈕,因為只有在服務 worker 處於活動狀態時,您才能實際訂閱推送訊息。

接下來要處理使用者想要啟用推播訊息的情況,但在進行這項操作之前,我們需要設定 Google 開發人員控制台專案,並在資訊清單中新增一些參數,以便使用 Firebase 雲端通訊 (FCM) (舊稱 Google 雲端通訊 (GCM))。

在 Firebase 開發人員控制台中建立專案

Chrome 會使用 FCM 處理推播訊息的傳送和遞送作業;不過,如要使用 FCM API,您必須在 Firebase 開發人員控制台上設定專案。

以下步驟適用於使用 FCM 的 Chrome、Android 版 Opera 和 Samsung Browser。我們會在文章稍後的部分討論這項功能在其他瀏覽器中的運作方式。

建立新的 Firebase 開發人員專案

首先,請在 https://console.firebase.google.com/ 中按一下「Create New Project」(建立新專案),建立新專案。

新 Firebase 專案螢幕截圖

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

Firebase 專案首頁

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

Firebase 專案設定選單

在設定頁面中,按一下「Cloud Messaging」分頁標籤。

Firebase 專案雲端通訊選單

這個頁面包含用於推播訊息的 API 金鑰 (稍後會用到),以及我們需要在下一節的網頁應用程式資訊清單中放入的寄件者 ID。

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

針對推播,我們需要新增含有 gcm_sender_id 欄位的資訊清單檔案,才能成功訂閱推播。只有 Chrome、Android 版 Opera 和 Samsung Browser 需要這個參數,才能使用 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';
        }
        });
    });
}

此時,您的網路應用程式已可接收推播訊息,但在我們將推播事件事件監聽器新增至服務 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 保持運作),直到 promise 完成為止;在這種情況下,傳遞至 event.waitUntil 的 promise 是從 showNotification() 傳回的 Promise。

通知標記可做為不重複通知的識別碼。如果我們傳送兩則推播訊息至同一個端點,且兩者之間有短暫延遲,並顯示同一個標記的通知,瀏覽器會顯示第一則通知,並在收到推播訊息時將其替換為第二則通知。

如果您想一次顯示多則通知,請使用其他代碼,或不使用任何代碼。我們將在本文稍後的部分,查看顯示通知的完整範例。我們先簡化一下,看看傳送推播訊息時是否會顯示這則通知。

傳送推送訊息

我們已訂閱推播訊息,服務工作者也已準備好顯示通知,因此是時候透過 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,如果是,請擷取 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 位址已列入該專案的許可清單。
  • 視您傳送的資料是 JSON 還是表單資料而定,使用 application/jsonapplication/x-www-form-urlencoded;charset=UTF-8 的適當 Content-Type 標頭。
  • 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 適用於 Android 的推播訊息。

開發後端邏輯時,請記住授權標頭和 POST 主體的格式是專屬於 FCM 端點,因此請偵測端點是否為 FCM,並根據條件新增標頭和格式化 POST 主體。對於其他瀏覽器 (希望未來 Chrome 也能支援),您需要導入Web Push 通訊協定

目前在 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偵錯網頁中的錯誤。如要對服務工作程式問題進行偵錯,您有兩種方法:

  1. 前往 chrome://inspect > Service workers。除了目前執行中的服務工作者,這個檢視畫面不會提供太多資訊。
  2. 前往 chrome://serviceworker-internals,您可以在這裡查看服務工作者的狀態,並查看錯誤 (如有)。這個頁面是暫時性的,等到開發人員工具提供類似的功能集後,就會移除。

對於服務工作程式新手,我能提供的最佳提示之一,就是使用名為「Open DevTools window and pause JavaScript execution on service worker startup for debugging」的核取方塊。這個核取方塊會在服務工作者開始時加入中斷點,並暫停執行,讓您可以繼續執行或逐步執行服務工作者指令碼,並查看是否發生任何問題。

螢幕截圖:顯示 serviceworker-internals 中的「暫停執行」核取方塊。

如果 FCM 和服務工作者的推送事件之間似乎有問題,您就無法查看 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 上偵錯服務工作程並不明顯。您必須前往 chrome://inspect,找出裝置,然後尋找名稱為「Worker pid:....」的清單項目,其中包含服務 worker 的網址。

螢幕截圖:顯示服務 worker 在 Chrome 檢查工具中的所在位置

推播通知的使用者體驗

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

Chrome 和開放網路上的推播訊息未來發展

本節將詳細說明此實作項目的部分 Chrome 專屬部分,以及與其他瀏覽器實作項目的差異。

網路推播通訊協定和端點

Push API 標準的優點在於,您可以使用端點,將其傳遞至伺服器,並透過實作 Web Push Protocol 傳送推播訊息。

Web Push 通訊協定是推播供應商可實作的全新標準,可讓開發人員不必擔心推播供應商為何人。這項通訊協定的概念是避免使用者需要註冊 API 金鑰,以及傳送格式特別的資料 (如使用 FCM 時)。

Chrome 是第一個實作 Push API 的瀏覽器,而 FCM 不支援 Web Push 通訊協定,因此 Chrome 需要 gcm_sender_id,您也需要使用 FCM 的 restful API。

Chrome 的最終目標是使用 Chrome 和 FCM 搭配網頁推播通訊協定。

在此之前,您需要偵測端點「https://fcm.googleapis.com/fcm/send」,並與其他端點分開處理,也就是以特定方式格式化酬載資料並新增授權金鑰。

How to Implement the Web Push Protocol?

Firefox Nightly 目前正在開發推播功能,很可能會是第一個導入 Web Push 通訊協定的瀏覽器。

常見問題

規格在哪裡?

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

如果我的網站有不同來源,或是同時有網站和原生網站,我可以避免收到重複通知嗎?

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

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

為什麼需要 gcm_sender_id?

這項設定是必要的,才能讓 Chrome、Android 版 Opera 和 Samsung 瀏覽器使用 Firebase 雲端通訊 (FCM) API。目標是在標準定案且 FCM 可支援時,使用 Web Push 通訊協定。

為什麼不使用 Web Sockets 或伺服器傳送事件 (EventSource)?

使用推播訊息的好處是,即使網頁關閉,服務工作者也會喚醒並顯示通知。關閉網頁或瀏覽器時,Web Sockets 和 EventSource 的連線會關閉。

如果我不需要背景事件提交功能,該怎麼辦?

如果您不需要背景提交,Web Sockets 就是不錯的選擇。

何時可以使用推播功能,而不顯示通知 (即靜默背景推播)?

目前尚未決定何時推出這項功能,但我們有意圖實作背景同步功能,雖然尚未決定或規範,但我們已討論過如何透過背景同步功能啟用無聲推播。

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

Service Worker 需要安全的來源,以確保 Service Worker 指令碼來自預期的來源,且並非來自中間人攻擊。目前這表示在實際網站上使用 HTTPS,不過在開發期間,本機會正常運作。

瀏覽器支援功能的運作方式為何?

Chrome 穩定版支援這項功能,Mozilla 也正在 Firefox Nightly 中推動這項功能。詳情請參閱「導入推送 API」錯誤,您也可以在這裡追蹤通知導入作業。

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

目前無法做到,但我們預計會新增支援功能,讓您取得目前顯示的通知清單。如果您有用途,需要在通知顯示建立後設定到期時間,我們很樂意瞭解那是什麼,因此請新增留言,我們會將其傳回給 Chrome 團隊。

如果您只想在特定時間後停止向使用者傳送推播通知,且不關心通知會顯示多久,可以使用 FCM 的有效時間 (ttl) 參數,請參閱這篇文章瞭解詳情。

Chrome 中的推播訊息有哪些限制?

這篇文章會說明幾項限制:

  • Chrome 使用 CCM 做為推播服務,因此會產生一些專屬要求。我們正在合作,看看日後是否可以解除其中一些限制。
  • 您必須在收到推播訊息時顯示通知。
  • 電腦版 Chrome 有個警告,如果 Chrome 未執行,就不會收到推播訊息。這與 ChromeOS 和 Android 不同,後者會一律接收推播訊息。

我們不應該使用 Permissions API 嗎?

Permission API 已在 Chrome 中實作,但不一定適用於所有瀏覽器。詳情請參閱這篇文章

為什麼 Chrome 在點選通知時不會開啟先前的分頁?

這項問題只會影響目前未由 Service Worker 控管的網頁。您可以參閱這個網頁來瞭解詳情。

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

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

詳情請參閱這篇文章

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

FCM 提供「collapse_key」參數,可用來告知 FCM 將任何具有相同「collapse_key」的待處理訊息,替換為新訊息。

詳情請參閱這篇文章