Thông báo đẩy trên web mở

Nếu bạn hỏi các nhà phát triển về những tính năng trên thiết bị di động bị thiếu trên web, thì thông báo đẩy sẽ luôn ở vị trí cao trong danh sách.

Thông báo đẩy cho phép người dùng chọn nhận thông tin cập nhật kịp thời từ các trang web mà họ yêu thích và cho phép bạn thu hút lại họ một cách hiệu quả bằng nội dung hấp dẫn, được cá nhân hoá.

Kể từ Chrome phiên bản 42, nhà phát triển có thể sử dụng Push APINotification API.

API Đẩy trong Chrome dựa vào một số công nghệ, bao gồm Tệp kê khai ứng dụng webTrình chạy dịch vụ. Trong bài đăng này, chúng ta sẽ xem xét từng công nghệ trong số này, nhưng chỉ ở mức tối thiểu để có thể chạy tính năng nhắn tin đẩy. Để hiểu rõ hơn về một số tính năng khác của tệp kê khai và chức năng ngoại tuyến của worker dịch vụ, vui lòng xem các đường liên kết ở trên.

Chúng ta cũng sẽ xem xét những nội dung sẽ được thêm vào API trong các phiên bản Chrome trong tương lai, và cuối cùng là phần Câu hỏi thường gặp.

Triển khai Thông báo đẩy cho Chrome

Phần này mô tả từng bước bạn cần hoàn tất để hỗ trợ tính năng thông báo đẩy trong ứng dụng web.

Đăng ký Trình chạy dịch vụ

Có một phần phụ thuộc là có một worker dịch vụ để triển khai thông báo đẩy cho web. Nguyên nhân là do khi nhận được một thông báo đẩy, trình duyệt có thể khởi động một trình chạy dịch vụ. Trình chạy này chạy trong nền mà không có trang đang mở và gửi một sự kiện để bạn có thể quyết định cách xử lý thông báo đẩy đó.

Dưới đây là ví dụ về cách bạn đăng ký một trình chạy dịch vụ trong ứng dụng web của mình. Khi quá trình đăng ký hoàn tất thành công, chúng ta sẽ gọi initialiseState(). Chúng ta sẽ sớm đề cập đến vấn đề này.

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.');
    }
});

Trình xử lý lượt nhấp vào nút sẽ đăng ký hoặc huỷ đăng ký người dùng nhận thông báo đẩy. isPushEnabled là một biến toàn cục chỉ theo dõi xem thông báo đẩy hiện có được đăng ký hay không. Các biến này sẽ được tham chiếu trong suốt các đoạn mã.

Sau đó, chúng ta kiểm tra để đảm bảo rằng trình chạy dịch vụ được hỗ trợ trước khi đăng ký tệp service-worker.js có logic để xử lý thông báo đẩy. Ở đây, chúng ta chỉ cần cho trình duyệt biết rằng tệp JavaScript này là worker dịch vụ cho trang web của chúng ta.

Thiết lập trạng thái ban đầu

Ví dụ về trải nghiệm người dùng khi bật và tắt tính năng nhắn tin đẩy trong Chrome.

Sau khi đăng ký worker dịch vụ, chúng ta cần thiết lập trạng thái của giao diện người dùng.

Người dùng sẽ mong muốn có một giao diện người dùng đơn giản để bật hoặc tắt thông báo đẩy cho trang web của bạn, đồng thời họ muốn giao diện người dùng đó luôn cập nhật mọi thay đổi xảy ra. Nói cách khác, nếu họ bật thông báo đẩy cho trang web của bạn, rời đi và quay lại sau một tuần, giao diện người dùng của bạn sẽ làm nổi bật rằng thông báo đẩy đã được bật.

Bạn có thể tìm thấy một số nguyên tắc về trải nghiệm người dùng trong tài liệu này. Trong bài viết này, chúng tôi sẽ tập trung vào các khía cạnh kỹ thuật.

Tại thời điểm này, bạn có thể nghĩ rằng chỉ có hai trạng thái để xử lý, đó là bật hoặc tắt. Tuy nhiên, có một số trạng thái khác xung quanh thông báo mà bạn cần tính đến.

Sơ đồ nêu bật các điểm khác nhau cần cân nhắc và trạng thái đẩy trong Chrome

Có một số API mà chúng ta cần kiểm tra trước khi bật nút và nếu mọi thứ đều được hỗ trợ, chúng ta có thể bật giao diện người dùng và đặt trạng thái ban đầu để cho biết liệu người dùng có đăng ký nhận thông báo đẩy hay không.

Vì phần lớn các bước kiểm tra này đều dẫn đến việc giao diện người dùng của chúng tôi bị vô hiệu hoá, bạn nên đặt trạng thái ban đầu thành tắt. Điều này cũng giúp tránh mọi nhầm lẫn nếu có vấn đề với JavaScript của trang, chẳng hạn như không thể tải tệp JS xuống hoặc người dùng đã tắt JavaScript.

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

Với trạng thái ban đầu này, chúng ta có thể thực hiện các bước kiểm tra nêu trên trong phương thức initialiseState(), tức là sau khi đăng ký worker dịch vụ.

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

Tổng quan ngắn gọn về các bước này:

  • Chúng ta kiểm tra để đảm bảo showNotification có trong nguyên mẫu ServiceWorkerRegistration. Nếu không có thông báo này, chúng ta sẽ không thể hiển thị thông báo từ trình chạy dịch vụ khi nhận được thông báo đẩy.
  • Chúng ta kiểm tra Notification.permission hiện tại để đảm bảo rằng đó không phải là "denied". Nếu quyền bị từ chối, bạn sẽ không thể hiển thị thông báo cho đến khi người dùng thay đổi quyền theo cách thủ công trong trình duyệt.
  • Để kiểm tra xem tính năng nhắn tin đẩy có được hỗ trợ hay không, chúng ta kiểm tra để đảm bảo PushManager có sẵn trong đối tượng cửa sổ.
  • Cuối cùng, chúng ta đã sử dụng pushManager.getSubscription() để kiểm tra xem chúng ta có gói thuê bao hay không. Nếu có, chúng tôi sẽ gửi thông tin đăng ký đến máy chủ để đảm bảo chúng tôi có thông tin chính xác và thiết lập giao diện người dùng để cho biết tính năng nhắn tin đẩy đã được bật hay chưa. Chúng ta sẽ xem xét những thông tin chi tiết nào có trong đối tượng gói thuê bao ở phần sau của bài viết này.

Chúng ta đợi cho đến khi navigator.serviceWorker.ready được phân giải để kiểm tra gói thuê bao và bật nút đẩy vì chỉ sau khi worker dịch vụ hoạt động, bạn mới có thể thực sự đăng ký nhận thông báo đẩy.

Bước tiếp theo là xử lý khi người dùng muốn bật thông báo đẩy, nhưng trước khi có thể làm việc này, chúng ta cần thiết lập một dự án trên Google Developer Console và thêm một số tham số vào tệp kê khai để sử dụng Firebase Cloud Messaging (FCM), trước đây gọi là Google Cloud Messaging (GCM).

Tạo dự án trên Firebase Developer Console

Chrome sử dụng FCM để xử lý việc gửi và phân phối thông báo đẩy; tuy nhiên, để sử dụng API FCM, bạn cần thiết lập một dự án trên Bảng điều khiển dành cho nhà phát triển Firebase.

Các bước sau đây dành riêng cho Chrome, Opera cho Android và Trình duyệt Samsung. Các trình duyệt này sử dụng FCM. Chúng ta sẽ thảo luận về cách hoạt động của tính năng này trong các trình duyệt khác ở phần sau của bài viết.

Tạo Dự án nhà phát triển Firebase mới

Để bắt đầu, bạn cần tạo một dự án mới trên https://console.firebase.google.com/ bằng cách nhấp vào "Tạo dự án mới".

Ảnh chụp màn hình New Firebase Project (Dự án Firebase mới)

Thêm tên dự án, tạo dự án và bạn sẽ được chuyển đến trang tổng quan về dự án:

Trang chủ dự án Firebase

Trên trang tổng quan này, hãy nhấp vào biểu tượng bánh răng bên cạnh tên dự án ở góc trên cùng bên trái rồi nhấp vào "Cài đặt dự án".

Trình đơn cài đặt dự án Firebase

Trong trang cài đặt, nhấp vào tab 'Gửi thông báo qua đám mây'.

Trình đơn Gửi thông báo qua đám mây của dự án Firebase

Trang này chứa khoá API để gửi thông báo đẩy mà chúng ta sẽ sử dụng sau này, cũng như mã nhận dạng người gửi mà chúng ta cần đưa vào tệp kê khai ứng dụng web trong phần tiếp theo.

Thêm tệp kê khai ứng dụng web

Đối với thông báo đẩy, chúng ta cần thêm một tệp kê khai có trường gcm_sender_id để đăng ký thông báo đẩy thành công. Chỉ Trình duyệt Chrome, Opera dành cho Android và Samsung yêu cầu thông số này để có thể sử dụng FCM / GCM.

Các trình duyệt này sử dụng gcm_sender_id khi đăng ký thiết bị của người dùng bằng FCM. Điều này có nghĩa là FCM có thể xác định thiết bị của người dùng và đảm bảo rằng mã nhận dạng người gửi của bạn khớp với khoá API tương ứng, đồng thời người dùng đã cho phép máy chủ của bạn gửi thông báo đẩy cho họ.

Dưới đây là một tệp kê khai cực kỳ đơn giản:

{
    "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>"
}

Bạn cần đặt giá trị gcm_sender_id thành mã nhận dạng người gửi trong Dự án Firebase.

Sau khi bạn lưu tệp kê khai trong dự án (manifest.json là tên tốt), hãy tham chiếu tệp đó từ HTML bằng thẻ sau trong phần đầu trang.

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

Nếu không thêm tệp kê khai web có các tham số này, bạn sẽ nhận được trường hợp ngoại lệ khi cố gắng đăng ký cho người dùng để đẩy thông báo (với lỗi "Registration failed - no sender id provided" hoặc "Registration failed - permission denied").

Đăng ký nhận thông báo đẩy

Bây giờ, bạn đã thiết lập xong tệp kê khai, bạn có thể quay lại JavaScript của trang web.

Để đăng ký, bạn phải gọi phương thức subscribe() trên đối tượng PushManager mà bạn truy cập thông qua ServiceWorkerRegistration.

Thao tác này sẽ yêu cầu người dùng cấp cho nguồn gốc của bạn quyền gửi thông báo đẩy. Nếu không có quyền này, bạn sẽ không thể đăng ký thành công.

Nếu lời hứa do phương thức subscribe() trả về được phân giải, bạn sẽ được cung cấp một đối tượng PushSubscription chứa một điểm cuối.

Bạn phải lưu điểm cuối trên máy chủ của mình cho từng người dùng, vì bạn sẽ cần các điểm cuối này để gửi thông báo đẩy vào lúc khác.

Mã sau đây sẽ đăng ký người dùng để nhận thông báo đẩy:

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

Tại thời điểm này, ứng dụng web của bạn đã sẵn sàng nhận thông báo đẩy, mặc dù sẽ không có gì xảy ra cho đến khi chúng ta thêm trình nghe sự kiện đẩy vào tệp trình chạy dịch vụ của mình.

Trình nghe sự kiện đẩy của trình chạy dịch vụ

Khi nhận được thông báo đẩy (chúng ta sẽ thảo luận về cách thực sự gửi thông báo đẩy trong phần tiếp theo), một sự kiện đẩy sẽ được gửi trong worker dịch vụ. Tại thời điểm đó, bạn cần hiển thị một thông báo.

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

Mã này đăng ký trình nghe sự kiện đẩy và hiển thị thông báo có tiêu đề, nội dung, biểu tượng và thẻ thông báo được xác định trước. Một điểm tinh tế cần làm nổi bật trong ví dụ này là phương thức event.waitUntil(). Phương thức này nhận một lời hứa và kéo dài thời gian hoạt động của trình xử lý sự kiện (hoặc có thể coi là duy trì hoạt động của worker dịch vụ), cho đến khi lời hứa được giải quyết; Trong trường hợp này, lời hứa được truyền đến event.waitUntil là Lời hứa được trả về từ showNotification().

Thẻ thông báo đóng vai trò là giá trị nhận dạng cho các thông báo riêng biệt. Nếu chúng ta đã gửi hai thông báo đẩy đến cùng một điểm cuối, với độ trễ ngắn giữa các thông báo đó và hiển thị thông báo bằng cùng một thẻ, thì trình duyệt sẽ cho thấy thông báo đầu tiên rồi thay thế bằng thông báo thứ hai khi nhận được thông báo đẩy.

Nếu bạn muốn hiển thị nhiều thông báo cùng một lúc, hãy sử dụng một thẻ khác hoặc không dùng thẻ nào. Chúng ta sẽ xem xét một ví dụ hoàn chỉnh hơn về cách hiển thị thông báo ở phần sau của bài đăng này. Hiện tại, hãy đơn giản hoá mọi thứ và xem việc gửi thông báo đẩy có hiển thị thông báo này hay không.

Gửi thông báo đẩy

Chúng tôi đã đăng ký nhận thông báo đẩy và trình chạy dịch vụ của chúng tôi đã sẵn sàng hiển thị thông báo, vì vậy, đã đến lúc gửi thông báo đẩy qua FCM.

Cách này chỉ áp dụng cho các trình duyệt sử dụng FCM.

Khi bạn gửi biến PushSubscription.endpoint đến máy chủ, điểm cuối cho FCM sẽ là đặc biệt. Tham số này có tham số ở cuối URL là registration_id.

Ví dụ về điểm cuối:

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

URL FCM là:

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

registration_id sẽ là:

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

Điều này áp dụng riêng cho những trình duyệt sử dụng FCM. Trong trình duyệt thông thường, bạn chỉ cần lấy một điểm cuối và gọi điểm cuối đó theo cách chuẩn và điểm cuối đó sẽ hoạt động bất kể URL.

Điều này có nghĩa là trên máy chủ của bạn, bạn cần kiểm tra xem điểm cuối có phải là dành cho FCM hay không và nếu có, hãy trích xuất registration_id. Để thực hiện việc này bằng Python, bạn có thể làm những việc như:

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

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

Sau khi có mã nhận dạng đăng ký, bạn có thể thực hiện lệnh gọi đến API FCM. Bạn có thể tìm thấy tài liệu tham khảo về API FCM tại đây.

Sau đây là những khía cạnh chính cần nhớ khi gọi FCM:

  • Bạn phải đặt tiêu đề Authorization (Uỷ quyền) có giá trị là key=&lt;YOUR_API_KEY&gt; khi gọi API, trong đó &lt;YOUR_API_KEY&gt; là khoá API của dự án Firebase.
    • FCM sử dụng khoá API để tìm mã nhận dạng người gửi thích hợp, đảm bảo người dùng đã cấp quyền cho dự án của bạn và cuối cùng là đảm bảo địa chỉ IP của máy chủ có trong danh sách cho phép cho dự án đó.
  • Tiêu đề Content-Type thích hợp là application/json hoặc application/x-www-form-urlencoded;charset=UTF-8 tuỳ thuộc vào việc bạn gửi dữ liệu dưới dạng JSON hay dữ liệu biểu mẫu.
  • Một mảng registration_ids – đây là mã nhận dạng đăng ký mà bạn sẽ trích xuất từ các điểm cuối của người dùng.

Vui lòng tham khảo tài liệu về cách gửi thông báo đẩy từ máy chủ của bạn. Tuy nhiên, để kiểm tra nhanh worker dịch vụ, bạn có thể sử dụng cURL để gửi thông báo đẩy đến trình duyệt.

Hoán đổi &lt;YOUR_API_KEY&gt;&lt;YOUR_REGISTRATION_ID&gt; trong lệnh cURL này bằng lệnh cURL của bạn và chạy trên một thiết bị đầu cuối.

Bạn sẽ thấy một thông báo thú vị:

    curl --header "Authorization: key=<YOUR_API_KEY>" --header
    "Content-Type: application/json" https://fcm.googleapis.com/fcm/send -d
    "{\"registration_ids\":[\"<YOUR_REGISTRATION_ID>\"]}"
Ví dụ về thông báo đẩy từ Chrome cho Android.

Khi phát triển logic phụ trợ, hãy nhớ rằng tiêu đề Uỷ quyền và định dạng của phần nội dung POST là dành riêng cho điểm cuối FCM, vì vậy, hãy phát hiện thời điểm điểm cuối là dành cho FCM và thêm tiêu đề và định dạng phần nội dung POST theo điều kiện. Đối với các trình duyệt khác (và hy vọng là Chrome trong tương lai), bạn cần triển khai Giao thức đẩy web.

Một điểm hạn chế của việc triển khai hiện tại của Push API trong Chrome là bạn không thể gửi bất kỳ dữ liệu nào bằng thông báo đẩy. Không, không có gì. Lý do là trong quá trình triển khai trong tương lai, dữ liệu tải trọng sẽ phải được mã hoá trên máy chủ của bạn trước khi được gửi đến điểm cuối nhắn tin đẩy. Bằng cách này, điểm cuối, bất kể nhà cung cấp dịch vụ đẩy nào, sẽ không thể dễ dàng xem nội dung của thông báo đẩy. Điều này cũng giúp ngăn chặn các lỗ hổng bảo mật khác như chứng chỉ HTTPS xác thực kém và các cuộc tấn công xen giữa giữa máy chủ và trình cung cấp dịch vụ đẩy. Tuy nhiên, phương thức mã hoá này chưa được hỗ trợ, vì vậy, trong thời gian chờ đợi, bạn cần thực hiện một lệnh tìm nạp để lấy thông tin cần thiết nhằm điền thông báo.

Ví dụ đầy đủ hơn về sự kiện đẩy

Thông báo mà chúng ta đã thấy cho đến nay khá cơ bản và về mặt mẫu, thông báo này khá kém trong việc đề cập đến trường hợp sử dụng thực tế.

Thực tế, hầu hết mọi người sẽ muốn nhận một số thông tin từ máy chủ của họ trước khi hiển thị thông báo. Đây có thể là dữ liệu để điền sẵn tiêu đề và thông báo của thông báo bằng một nội dung cụ thể, hoặc tiến thêm một bước và lưu một số trang hoặc dữ liệu vào bộ nhớ đệm để khi người dùng nhấp vào thông báo, mọi thứ sẽ có sẵn ngay khi trình duyệt mở ra, ngay cả khi mạng không hoạt động tại thời điểm đó.

Trong mã sau, chúng ta tìm nạp một số dữ liệu từ một API, chuyển đổi phản hồi thành một đối tượng và sử dụng đối tượng đó để điền thông báo.

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

Xin nhắc lại rằng event.waitUntil() sẽ nhận một lời hứa dẫn đến lời hứa do showNotification() trả về, nghĩa là trình nghe sự kiện của chúng ta sẽ không thoát cho đến khi lệnh gọi fetch() không đồng bộ hoàn tất và thông báo xuất hiện.

Bạn sẽ thấy chúng tôi hiển thị thông báo ngay cả khi có lỗi. Lý do là nếu không, Chrome sẽ hiển thị thông báo chung của riêng mình.

Mở URL khi người dùng nhấp vào thông báo

Khi người dùng nhấp vào một thông báo, một sự kiện notificationclick sẽ được gửi trong worker dịch vụ. Trong trình xử lý, bạn có thể thực hiện hành động thích hợp, chẳng hạn như lấy tiêu điểm một thẻ hoặc mở một cửa sổ có URL cụ thể:

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

Ví dụ này mở trình duyệt đến thư mục gốc của trang web, bằng cách tập trung vào một thẻ cùng nguồn gốc hiện có (nếu có), và mở một thẻ mới.

Có một bài đăng dành riêng cho một số việc bạn có thể làm với Notification API tại đây.

Huỷ đăng ký thiết bị của người dùng

Bạn đã đăng ký thiết bị của người dùng và họ đang nhận được thông báo đẩy, nhưng làm cách nào để bạn có thể huỷ đăng ký?

Việc chính cần làm để huỷ đăng ký thiết bị của người dùng là gọi phương thức unsubscribe() trên đối tượng PushSubscription và xoá điểm cuối khỏi máy chủ của bạn (để bạn không gửi thông báo đẩy mà bạn biết rằng mình sẽ không nhận được thông báo này). Mã dưới đây thực hiện chính xác điều này:

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

Cập nhật gói thuê bao

Các gói thuê bao có thể không đồng bộ giữa FCM và máy chủ của bạn. Đảm bảo máy chủ của bạn phân tích cú pháp nội dung phản hồi của lệnh gửi POST của API FCM, tìm kết quả error:NotRegisteredcanonical_id, như được giải thích trong tài liệu về FCM.

Các gói thuê bao cũng có thể không đồng bộ giữa worker dịch vụ và máy chủ. Ví dụ: sau khi đăng ký/huỷ đăng ký thành công, một kết nối mạng không ổn định có thể khiến bạn không cập nhật được máy chủ; hoặc người dùng có thể thu hồi quyền gửi thông báo, điều này sẽ kích hoạt việc tự động huỷ đăng ký. Xử lý các trường hợp như vậy bằng cách định kỳ kiểm tra kết quả của serviceWorkerRegistration.pushManager.getSubscription() (ví dụ: khi tải trang) và đồng bộ hoá kết quả đó với máy chủ. Bạn cũng nên tự động đăng ký lại nếu không còn gói thuê bao và Notification.permission == 'granted'.

Trong sendSubscriptionToServer(), bạn cần cân nhắc cách xử lý các yêu cầu mạng không thành công khi cập nhật endpoint. Có một giải pháp là theo dõi trạng thái của endpoint trong cookie để xác định xem máy chủ của bạn có cần thông tin chi tiết mới nhất hay không.

Tất cả các bước trên sẽ giúp bạn triển khai đầy đủ tính năng nhắn tin đẩy trên web trong Chrome 46. Vẫn còn một số tính năng theo thông số kỹ thuật sẽ giúp bạn dễ dàng hơn (chẳng hạn như API tiêu chuẩn để kích hoạt thông báo đẩy), nhưng bản phát hành này cho phép bạn bắt đầu xây dựng thông báo đẩy vào ứng dụng web ngay hôm nay.

Cách gỡ lỗi ứng dụng web

Trong khi triển khai thông báo đẩy, lỗi sẽ nằm ở một trong hai vị trí: trang hoặc worker dịch vụ.

Bạn có thể gỡ lỗi trên trang bằng DevTools. Để gỡ lỗi các vấn đề về trình chạy dịch vụ, bạn có 2 lựa chọn:

  1. Truy cập vào chrome://inspect > Service workers (chrome://kiểm tra > Trình chạy dịch vụ). Chế độ xem này không cung cấp nhiều thông tin ngoài các worker dịch vụ đang chạy.
  2. Truy cập vào chrome://serviceworker-internals. Từ đây, bạn có thể xem trạng thái của trình chạy dịch vụ cũng như xem các lỗi (nếu có). Trang này là trang tạm thời cho đến khi Công cụ cho nhà phát triển có một bộ tính năng tương tự.

Một trong những mẹo hay nhất mà tôi có thể chia sẻ với những người mới sử dụng worker là sử dụng hộp đánh dấu có tên "Mở cửa sổ DevTools và tạm dừng quá trình thực thi JavaScript khi khởi động worker để gỡ lỗi". Hộp đánh dấu này sẽ thêm một điểm ngắt ở đầu trình chạy dịch vụ và tạm dừng quá trình thực thi, cho phép bạn tiếp tục hoặc từng bước thực hiện tập lệnh trình chạy dịch vụ và xem liệu bạn có gặp vấn đề nào không.

Ảnh chụp màn hình cho thấy vị trí của hộp đánh dấu tạm dừng thực thi trên serviceworker-internals.

Nếu có vẻ như có vấn đề giữa FCM và sự kiện đẩy của worker dịch vụ, thì bạn không thể làm gì nhiều để gỡ lỗi vấn đề này vì không có cách nào để bạn biết liệu Chrome có nhận được gì hay không. Điều quan trọng cần đảm bảo là phản hồi từ FCM thành công khi máy chủ của bạn thực hiện lệnh gọi API. Mã sẽ có dạng như sau:

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

Hãy lưu ý phản hồi "success": 1. Nếu bạn thấy thông báo lỗi, thì điều đó cho thấy có gì đó không ổn với mã đăng ký FCM và thông báo đẩy không được gửi đến Chrome.

Gỡ lỗi Worker dịch vụ trên Chrome cho Android

Hiện tại, việc gỡ lỗi trình chạy dịch vụ trên Chrome dành cho Android chưa rõ ràng. Bạn cần chuyển đến chrome://inspect, tìm thiết bị của mình và tìm một mục danh sách có tên "Worker pid:...." (Mã nhận dạng của worker:....") có URL của worker dịch vụ.

Ảnh chụp màn hình cho thấy vị trí của trình chạy dịch vụ trong Chrome inspect

Trải nghiệm người dùng cho thông báo đẩy

Nhóm Chrome đã tổng hợp một tài liệu về các phương pháp hay nhất cho trải nghiệm người dùng thông báo đẩy, cũng như một tài liệu trình bày một số trường hợp hiếm gặp khi làm việc với thông báo đẩy.

Tương lai của tính năng Thông báo đẩy trên Chrome và Web mở

Phần này trình bày một số chi tiết về một số phần cụ thể của Chrome trong quá trình triển khai này mà bạn cần lưu ý và sự khác biệt giữa cách triển khai này với các cách triển khai trình duyệt khác.

Giao thức đẩy web và điểm cuối

Điểm hay của tiêu chuẩn API Đẩy là bạn có thể lấy điểm cuối, truyền điểm cuối đó đến máy chủ và gửi thông báo đẩy bằng cách triển khai Giao thức đẩy web.

Giao thức đẩy web là một tiêu chuẩn mới mà các trình cung cấp dịch vụ đẩy có thể triển khai, cho phép các nhà phát triển không phải lo lắng về việc ai là trình cung cấp dịch vụ đẩy. Ý tưởng ở đây là giúp tránh phải đăng ký các khoá API và gửi dữ liệu có định dạng đặc biệt, như bạn phải làm với FCM.

Chrome là trình duyệt đầu tiên triển khai Push API và FCM không hỗ trợ giao thức Web Push. Đó là lý do tại sao Chrome yêu cầu gcm_sender_id và bạn cần sử dụng API REST cho FCM.

Mục tiêu cuối cùng của Chrome là chuyển sang sử dụng Giao thức đẩy web với Chrome và FCM.

Cho đến thời điểm đó, bạn cần phát hiện điểm cuối "https://fcm.googleapis.com/fcm/send" và xử lý điểm cuối này riêng biệt với các điểm cuối khác, tức là định dạng dữ liệu tải trọng theo cách cụ thể và thêm Khoá uỷ quyền.

Làm cách nào để triển khai Giao thức đẩy web?

Firefox Nightly hiện đang triển khai tính năng đẩy và có thể sẽ là trình duyệt đầu tiên triển khai Giao thức đẩy web.

Câu hỏi thường gặp

Thông số kỹ thuật ở đâu?

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

Tôi có thể ngăn thông báo trùng lặp nếu sự hiện diện trên web của tôi có nhiều nguồn gốc hoặc nếu tôi có cả sự hiện diện trên web và sự hiện diện gốc không?

Hiện tại chưa có giải pháp cho vấn đề này, nhưng bạn có thể theo dõi tiến trình trên Chromium.

Trường hợp lý tưởng là có một số loại mã nhận dạng cho thiết bị của người dùng, sau đó ở phía máy chủ so khớp mã nhận dạng của ứng dụng gốc và gói thuê bao của ứng dụng web, rồi quyết định xem sẽ gửi thông báo đẩy đến mã nào. Bạn có thể thực hiện việc này thông qua kích thước màn hình, mô hình thiết bị, chia sẻ khoá đã tạo giữa ứng dụng web và ứng dụng gốc, nhưng mỗi phương pháp đều có ưu và khuyết điểm.

Tại sao tôi cần có gcm_sender_id?

Bạn cần phải cấp quyền này để Chrome, Opera cho Android và Trình duyệt Samsung có thể sử dụng API Giải pháp gửi thông báo qua đám mây của Firebase (FCM). Mục tiêu là sử dụng giao thức Web Push khi tiêu chuẩn này được hoàn thiện và FCM có thể hỗ trợ giao thức này.

Tại sao không sử dụng Web Sockets hoặc Sự kiện do máy chủ gửi (EventSource)?

Lợi thế của việc sử dụng thông báo đẩy là ngay cả khi trang của bạn bị đóng, trình chạy dịch vụ sẽ được đánh thức và có thể hiển thị thông báo. Web Sockets và EventSource sẽ bị đóng kết nối khi trang hoặc trình duyệt bị đóng.

Nếu tôi không cần phân phối sự kiện nền thì sao?

Nếu bạn không cần phân phối ở chế độ nền, thì Web Sockets là một lựa chọn tuyệt vời.

Khi nào tôi có thể sử dụng tính năng đẩy mà không hiển thị thông báo (tức là đẩy trong nền ở chế độ im lặng)?

Hiện chưa có tiến trình về thời điểm ra mắt tính năng này, nhưng chúng tôi có ý định triển khai tính năng đồng bộ hoá ở chế độ nền. Mặc dù chưa được quyết định hoặc quy định, nhưng chúng tôi có một số nội dung thảo luận về việc bật tính năng đẩy không âm thanh bằng tính năng đồng bộ hoá ở chế độ nền.

Tại sao việc này yêu cầu HTTPS? Làm cách nào để khắc phục vấn đề này trong quá trình phát triển?

Trình chạy dịch vụ yêu cầu nguồn gốc an toàn để đảm bảo rằng tập lệnh của trình chạy dịch vụ là từ nguồn gốc dự kiến và không phải là do một cuộc tấn công giả mạo. Hiện tại, điều đó có nghĩa là sử dụng HTTPS trên các trang web đang hoạt động, mặc dù localhost sẽ hoạt động trong quá trình phát triển.

Hoạt động hỗ trợ trình duyệt diễn ra như thế nào?

Chrome hỗ trợ trong phiên bản ổn định và Mozilla đang triển khai tính năng đẩy trong Firefox Nightly. Hãy xem lỗi triển khai Push API để biết thêm thông tin và bạn có thể theo dõi cách triển khai Thông báo của họ tại đây.

Tôi có thể xoá một thông báo sau một khoảng thời gian nhất định không?

Hiện tại, bạn chưa thể làm việc này nhưng chúng tôi dự định sẽ hỗ trợ thêm để lấy danh sách các thông báo hiện đang hiển thị. Nếu bạn có một trường hợp sử dụng để đặt thời hạn cho thông báo sau khi thông báo được tạo, chúng tôi rất muốn biết đó là gì, vì vậy hãy thêm nhận xét và chúng tôi sẽ chuyển lại cho nhóm Chrome.

Nếu chỉ cần ngừng gửi thông báo đẩy cho người dùng sau một khoảng thời gian nhất định và không quan tâm đến thời lượng hiển thị của thông báo, thì bạn có thể sử dụng tham số thời gian tồn tại (ttl) của FCM, tìm hiểu thêm tại đây.

Tính năng nhắn tin đẩy trong Chrome có những hạn chế gì?

Có một vài giới hạn được nêu trong bài đăng này:

  • Việc Chrome sử dụng CCM làm dịch vụ đẩy sẽ tạo ra một số yêu cầu độc quyền. Chúng tôi đang cùng nhau nỗ lực để xem liệu có thể gỡ bỏ một số hạn chế này trong tương lai hay không.
  • Bạn phải hiển thị thông báo khi nhận được thông báo đẩy.
  • Chrome trên máy tính có cảnh báo rằng nếu Chrome không chạy, thì bạn sẽ không nhận được thông báo đẩy. Điều này khác với ChromeOS và Android, vốn luôn nhận được thông báo đẩy.

Không phải chúng ta nên sử dụng API Quyền sao?

API Quyền được triển khai trong Chrome, nhưng không nhất thiết phải hoạt động trên một số trình duyệt. Tìm hiểu thêm tại đây.

Tại sao Chrome không mở thẻ trước đó khi tôi nhấp vào một thông báo?

Vấn đề này chỉ ảnh hưởng đến những trang hiện không do trình chạy dịch vụ kiểm soát. Bạn có thể tìm hiểu thêm tại đây.

Điều gì sẽ xảy ra nếu thông báo đã lỗi thời vào thời điểm thiết bị của người dùng nhận được thông báo đẩy?

Bạn luôn phải hiển thị thông báo khi nhận được thông báo đẩy. Trong trường hợp bạn muốn gửi thông báo nhưng thông báo đó chỉ hữu ích trong một khoảng thời gian nhất định, bạn có thể sử dụng thông số "time_to_live" trên CCM để FCM không gửi thông báo đẩy nếu thông báo đó đã hết hạn.

Bạn có thể xem thêm thông tin tại đây.

Điều gì sẽ xảy ra nếu tôi gửi 10 thông báo đẩy nhưng chỉ muốn thiết bị nhận một thông báo?

FCM có một tham số "collapse_key" mà bạn có thể sử dụng để yêu cầu FCM thay thế mọi thông báo đang chờ xử lý có cùng "collapse_key" bằng thông báo mới.

Bạn có thể xem thêm thông tin tại đây.