ติดตามผู้ใช้เพื่อรับข้อความ Push

หากต้องการส่งข้อความ Push คุณต้องได้รับสิทธิ์จากผู้ใช้ก่อน แล้วจึงสมัครใช้บริการ Push ในอุปกรณ์ของผู้ใช้ ซึ่งเกี่ยวข้องกับการใช้ JavaScript API เพื่อรับออบเจ็กต์ PushSubscription แล้วส่งไปยังเซิร์ฟเวอร์

JavaScript API จะจัดการกระบวนการนี้อย่างตรงไปตรงมา คู่มือนี้จะอธิบายขั้นตอนทั้งหมด ซึ่งรวมถึงการตรวจหาฟีเจอร์ การขอสิทธิ์ และการจัดการกระบวนการสมัครใช้บริการ

การตรวจจับฟีเจอร์

ก่อนอื่น ให้ตรวจสอบว่าเบราว์เซอร์รองรับข้อความ Push หรือไม่ คุณตรวจสอบการรองรับพุชได้ด้วยการตรวจสอบ 2 รายการต่อไปนี้

  • ตรวจสอบ serviceWorker ในออบเจ็กต์ navigator
  • ตรวจสอบ PushManager ในออบเจ็กต์ window
if (!('serviceWorker' in navigator)) {
  // Service Worker isn't supported on this browser, disable or hide UI.
  return;
}

if (!('PushManager' in window)) {
  // Push isn't supported on this browser, disable or hide UI.
  return;
}

แม้ว่าการรองรับเบราว์เซอร์สำหรับทั้ง Service Worker และข้อความ Push จะเพิ่มขึ้น แต่ให้ตรวจหาทั้ง 2 ฟีเจอร์และปรับปรุงแอปพลิเคชันอย่างต่อเนื่องเสมอ

ลงทะเบียน Service Worker

หลังจากตรวจหาฟีเจอร์แล้ว คุณจะทราบว่าระบบรองรับ Service Worker และข้อความ Push ถัดไป ให้ลงทะเบียน Service Worker

เมื่อลงทะเบียน Service Worker คุณจะบอกเบราว์เซอร์ถึงตำแหน่งของไฟล์ Service Worker ไฟล์ดังกล่าวเป็นไฟล์ JavaScript แต่เบราว์เซอร์ให้สิทธิ์เข้าถึง API ของ Service Worker ซึ่งรวมถึงการรับส่งข้อความ Push กล่าวคือ เบราว์เซอร์จะเรียกใช้ไฟล์ในสภาพแวดล้อม Service Worker

หากต้องการลงทะเบียน Service Worker ให้เรียกใช้ navigator.serviceWorker.register() และส่งเส้นทางไปยังไฟล์ของคุณ เช่น

function registerServiceWorker() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      console.log('Service worker successfully registered.');
      return registration;
    })
    .catch(function (err) {
      console.error('Unable to register service worker.', err);
    });
}

ฟังก์ชันนี้จะบอกเบราว์เซอร์ถึงตำแหน่งของไฟล์ Service Worker ในกรณีนี้ ไฟล์ Service Worker จะอยู่ที่ /service-worker.js หลังจากที่คุณเรียกใช้ register() เบราว์เซอร์จะทำตามขั้นตอนต่อไปนี้

  1. ดาวน์โหลดไฟล์ Service Worker

  2. เรียกใช้ JavaScript

  3. หากไฟล์ทำงานได้อย่างถูกต้องโดยไม่มีข้อผิดพลาด สัญญาที่ register() แสดงผลจะได้รับการแก้ไข หากเกิดข้อผิดพลาด ระบบจะปฏิเสธ Promise

หมายเหตุ: หาก register() ปฏิเสธ ให้ตรวจสอบ JavaScript เพื่อหาการพิมพ์ผิดหรือข้อผิดพลาดในเครื่องมือสำหรับนักพัฒนาเว็บใน Chrome

เมื่อ register() แก้ไขปัญหาแล้ว ระบบจะแสดงผลเป็น ServiceWorkerRegistration คุณใช้การลงทะเบียนนี้เพื่อเข้าถึง PushManager API

ความเข้ากันได้ของเบราว์เซอร์กับ PushManager API

Browser Support

  • Chrome: 42.
  • Edge: 17.
  • Firefox: 44.
  • Safari: 16.

Source

กำลังขอสิทธิ์

หลังจากลงทะเบียน Service Worker และได้รับสิทธิ์แล้ว ให้ขอสิทธิ์จากผู้ใช้เพื่อส่งข้อความ Push

API สำหรับการขอสิทธิ์นั้นใช้งานง่าย อย่างไรก็ตาม API เพิ่งเปลี่ยนจากการใช้ Callback เป็นการแสดงผล Promise เนื่องจากคุณไม่สามารถระบุเวอร์ชัน API ที่เบราว์เซอร์ใช้ คุณจึงต้องใช้และจัดการทั้ง 2 เวอร์ชัน

function askPermission() {
  return new Promise(function (resolve, reject) {
    const permissionResult = Notification.requestPermission(function (result) {
      resolve(result);
    });

    if (permissionResult) {
      permissionResult.then(resolve, reject);
    }
  }).then(function (permissionResult) {
    if (permissionResult !== 'granted') {
      throw new Error("We weren't granted permission.");
    }
  });
}

ในโค้ดก่อนหน้า การเรียกใช้ Notification.requestPermission() จะแสดงข้อความแจ้งต่อผู้ใช้ดังนี้

ข้อความแจ้งสิทธิ์ที่แสดงใน Chrome บนเดสก์ท็อปและอุปกรณ์เคลื่อนที่

หลังจากที่ผู้ใช้โต้ตอบกับข้อความแจ้งสิทธิ์โดยเลือกอนุญาต บล็อก หรือปิดข้อความแจ้ง คุณจะได้รับผลลัพธ์เป็นสตริง 'granted', 'default' หรือ 'denied'

ในโค้ดตัวอย่าง สัญญาที่ askPermission() แสดงผลจะได้รับการแก้ไขหากได้รับสิทธิ์ ไม่เช่นนั้น ระบบจะแสดงข้อผิดพลาดและสัญญาจะถูกปฏิเสธ

จัดการกรณีที่เกิดขึ้นไม่บ่อยนักซึ่งผู้ใช้คลิกปุ่มบล็อก หากเกิดกรณีนี้ขึ้น เว็บแอปของคุณจะไม่สามารถขอสิทธิ์จากผู้ใช้อีกครั้งได้ ผู้ใช้ต้องเลิกบล็อกแอปของคุณด้วยตนเองโดยเปลี่ยนสถานะสิทธิ์ในแผงการตั้งค่า พิจารณาอย่างรอบคอบว่าจะขอสิทธิ์เมื่อใดและอย่างไร เพราะหากผู้ใช้คลิกบล็อก การเปลี่ยนใจจะทำได้ยาก

ผู้ใช้ส่วนใหญ่จะให้สิทธิ์หากเข้าใจสาเหตุที่แอปขอสิทธิ์

เอกสารนี้จะอธิบายวิธีที่เว็บไซต์ยอดนิยมบางแห่งขอสิทธิ์ในภายหลังในเอกสารนี้

สมัครใช้บริการ PushManager ให้ผู้ใช้

หลังจากลงทะเบียน Service Worker และได้รับสิทธิ์แล้ว คุณจะสมัครรับข้อมูลให้ผู้ใช้ได้โดยเรียกใช้ registration.pushManager.subscribe()

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

เมื่อเรียกใช้เมธอด subscribe() คุณจะส่งออบเจ็กต์ options ซึ่งประกอบด้วยพารามิเตอร์ที่จำเป็นและไม่บังคับ

ส่วนนี้จะอธิบายตัวเลือกที่คุณส่งได้

ตัวเลือก userVisibleOnly

เมื่อมีการเพิ่มการรับส่งข้อความ Push ลงในเบราว์เซอร์เป็นครั้งแรก นักพัฒนาแอปไม่แน่ใจเกี่ยวกับการส่งข้อความ Push โดยไม่แสดงการแจ้งเตือน ซึ่งมักเรียกว่า Silent Push เนื่องจากผู้ใช้ไม่ทราบว่ามีเหตุการณ์เกิดขึ้นในเบื้องหลัง

เนื่องจากนักพัฒนาแอปอาจติดตามตำแหน่งของผู้ใช้อย่างต่อเนื่องโดยที่ผู้ใช้ไม่ทราบ

เราได้เพิ่มตัวเลือก userVisibleOnly เพื่อหลีกเลี่ยงสถานการณ์นี้และช่วยให้ผู้เขียนข้อกำหนดพิจารณาวิธีที่ดีที่สุดในการรองรับฟีเจอร์นี้ การส่งค่า true เป็นข้อตกลงเชิงสัญลักษณ์กับเบราว์เซอร์ว่าเว็บแอปจะแสดงการแจ้งเตือนทุกครั้งที่ได้รับข้อความ Push (นั่นคือไม่มีการพุชแบบไม่มีเสียง)

คุณต้องส่งค่า true หากคุณไม่ระบุคีย์ userVisibleOnly หรือส่ง false คุณจะได้รับข้อผิดพลาดต่อไปนี้

Chrome currently only supports the Push API for subscriptions that will result
in user-visible messages. You can indicate this by calling
`pushManager.subscribe({userVisibleOnly: true})` instead. See
[https://goo.gl/yqv4Q4](https://goo.gl/yqv4Q4) for more details.

Chrome รองรับ Push API สำหรับการสมัครใช้บริการที่ส่งผลให้เกิดข้อความที่ผู้ใช้มองเห็นเท่านั้น ระบุข้อมูลนี้โดยเรียกใช้ pushManager.subscribe({userVisibleOnly: true}) ดูข้อมูลเพิ่มเติมได้ที่ https://goo.gl/yqv4Q4

ดูเหมือนว่า Chrome จะไม่ใช้ Silent Push แบบครอบคลุม แต่ผู้เขียนข้อกำหนดกำลังสำรวจ API บัดเจ็ตที่ช่วยให้เว็บแอปส่งข้อความพุชแบบไม่แสดงผลได้จำนวนหนึ่งตามการใช้งานเว็บแอป

ตัวเลือก applicationServerKey

เอกสารนี้เคยกล่าวถึงคีย์เซิร์ฟเวอร์ของแอปพลิเคชัน บริการพุชใช้คีย์เซิร์ฟเวอร์แอปพลิเคชันเพื่อระบุแอปพลิเคชันที่สมัครใช้บริการผู้ใช้ และเพื่อให้แน่ใจว่าแอปพลิเคชันเดียวกันจะส่งข้อความถึงผู้ใช้รายนั้น

คีย์เซิร์ฟเวอร์ของแอปพลิเคชันคือคู่คีย์สาธารณะและคีย์ส่วนตัวที่ไม่ซ้ำกันสำหรับแอปพลิเคชันของคุณ เก็บคีย์ส่วนตัวไว้เป็นความลับสำหรับแอปพลิเคชันของคุณ และแชร์คีย์สาธารณะได้อย่างอิสระ

ตัวเลือก applicationServerKey ที่ส่งไปยังการเรียก subscribe() คือคีย์สาธารณะของแอปพลิเคชัน เบราว์เซอร์จะส่งคีย์นี้ไปยังบริการพุชเมื่อสมัครรับข้อมูลผู้ใช้ ซึ่งจะช่วยให้บริการพุชเชื่อมโยงคีย์สาธารณะของแอปพลิเคชันกับ PushSubscription ของผู้ใช้ได้

แผนภาพต่อไปนี้แสดงขั้นตอนเหล่านี้

  1. โหลดเว็บแอปในเบราว์เซอร์และเรียกใช้ subscribe() โดยส่งคีย์เซิร์ฟเวอร์แอปพลิเคชันสาธารณะ
  2. จากนั้นเบราว์เซอร์จะส่งคำขอเครือข่ายไปยังบริการพุช ซึ่งจะสร้างปลายทาง เชื่อมโยงปลายทางนี้กับคีย์สาธารณะของแอปพลิเคชัน และแสดงผลปลายทางไปยังเบราว์เซอร์
  3. เบราว์เซอร์จะเพิ่มปลายทางนี้ลงใน PushSubscription ซึ่งสัญญา subscribe() จะแสดงผล

แผนภาพแสดงวิธีใช้คีย์เซิร์ฟเวอร์แอปพลิเคชันสาธารณะในเมธอด `subscribe()`

เมื่อส่งข้อความ Push ให้สร้างส่วนหัว Authorization ที่มีข้อมูลที่ลงนามด้วยคีย์ส่วนตัวของเซิร์ฟเวอร์แอปพลิเคชัน เมื่อบริการพุชได้รับคำขอให้ส่งข้อความพุช บริการจะตรวจสอบส่วนหัวการให้สิทธิ์ที่ลงนามนี้โดยค้นหาคีย์สาธารณะที่ลิงก์กับปลายทางที่ได้รับคำขอ หากลายเซ็นถูกต้อง บริการพุชจะทราบว่าคำขอมาจากเซิร์ฟเวอร์แอปพลิเคชันที่มีคีย์ส่วนตัวที่ตรงกัน ซึ่งเป็นมาตรการรักษาความปลอดภัยที่ป้องกันไม่ให้ผู้อื่นส่งข้อความถึงผู้ใช้แอปพลิเคชันของคุณ

แผนภาพแสดงวิธีใช้คีย์เซิร์ฟเวอร์แอปพลิเคชันส่วนตัวเมื่อส่งข้อความ

ในทางเทคนิคแล้ว applicationServerKey เป็นแบบไม่บังคับ อย่างไรก็ตาม การติดตั้งใช้งานที่ง่ายที่สุดใน Chrome จำเป็นต้องใช้ และเบราว์เซอร์อื่นๆ อาจต้องใช้ในอนาคต โดยจะใส่หรือไม่ใส่ก็ได้ใน Firefox

ข้อกำหนด VAPID จะกำหนดคีย์เซิร์ฟเวอร์ของแอปพลิเคชัน เมื่อเห็นการอ้างอิงถึงคีย์เซิร์ฟเวอร์ของแอปพลิเคชันหรือคีย์ VAPID โปรดทราบว่าคีย์ทั้ง 2 อย่างนี้เป็นคีย์เดียวกัน

สร้างคีย์เซิร์ฟเวอร์แอปพลิเคชัน

คุณสร้างชุดคีย์เซิร์ฟเวอร์แอปพลิเคชันแบบสาธารณะและส่วนตัวได้โดยใช้บรรทัดคำสั่ง Web Push เพื่อสร้างคีย์ดังนี้

    $ npm install -g web-push
    $ web-push generate-vapid-keys

สร้างคีย์เหล่านี้เพียงครั้งเดียวสำหรับแอปพลิเคชันของคุณ และตรวจสอบว่าคุณเก็บคีย์ส่วนตัวไว้เป็นส่วนตัว

สิทธิ์และ subscribe()

การเรียกใช้ subscribe() มีผลข้างเคียง 1 อย่าง หากเว็บแอปไม่มีสิทธิ์แสดงการแจ้งเตือนเมื่อคุณเรียกใช้ subscribe() เบราว์เซอร์จะขอสิทธิ์ให้คุณ วิธีนี้มีประโยชน์หาก UI ของคุณทำงานร่วมกับขั้นตอนดังกล่าว แต่หากต้องการควบคุมมากขึ้น (ซึ่งนักพัฒนาแอปส่วนใหญ่ต้องการ) ให้ใช้ Notification.requestPermission() API ที่เอกสารนี้กล่าวถึงก่อนหน้านี้

ภาพรวมของ PushSubscription

คุณเรียก subscribe() ส่งตัวเลือก และรับสัญญาที่แก้ไขเป็น PushSubscription เช่น

function subscribeUserToPush() {
  return navigator.serviceWorker
    .register('/service-worker.js')
    .then(function (registration) {
      const subscribeOptions = {
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array(
          'BEl62iUYgUivxIkv69yViEuiBIa-Ib9-SkvMeAtA3LFgDzkrxZJjSgSnfckjBJuBkr3qBUYIHBQFLXYp5Nksh8U',
        ),
      };

      return registration.pushManager.subscribe(subscribeOptions);
    })
    .then(function (pushSubscription) {
      console.log(
        'Received PushSubscription: ',
        JSON.stringify(pushSubscription),
      );
      return pushSubscription;
    });
}

ออบเจ็กต์ PushSubscription มีข้อมูลทั้งหมดที่จำเป็นในการส่งข้อความ Push ไปยังผู้ใช้รายนั้น หากพิมพ์เนื้อหาโดยใช้ JSON.stringify() คุณจะเห็นสิ่งต่อไปนี้

    {
      "endpoint": "https://some.pushservice.com/something-unique",
      "keys": {
        "p256dh":
    "BIPUL12DLfytvTajnryr2PRdAgXS3HGKiLqndGcJGabyhHheJYlNGCeXl1dn18gSJ1WAkAPIxr4gK0_dQds4yiI=",
        "auth":"FPssNDTKnInHVndSTdbKFw=="
      }
    }

endpoint คือ URL ของบริการพุช หากต้องการทริกเกอร์ข้อความ Push ให้ส่งคำขอ POST ไปยัง URL นี้

ออบเจ็กต์ keys มีค่าที่ใช้ในการเข้ารหัสข้อมูลข้อความที่ส่งพร้อมกับข้อความ Push (เอกสารนี้จะกล่าวถึงการเข้ารหัสข้อความในภายหลัง)

ส่งการสมัครใช้บริการไปยังเซิร์ฟเวอร์

หลังจากมีการสมัครใช้บริการพุชแล้ว ให้ส่งไปยังเซิร์ฟเวอร์ คุณกำหนดวิธีส่งได้ แต่เราขอแนะนำให้ใช้ JSON.stringify() เพื่อดึงข้อมูลที่จำเป็นทั้งหมดจากออบเจ็กต์การสมัครใช้บริการ หรือจะประกอบผลลัพธ์เดียวกันด้วยตนเองก็ได้ เช่น

const subscriptionObject = {
  endpoint: pushSubscription.endpoint,
  keys: {
    p256dh: pushSubscription.getKeys('p256dh'),
    auth: pushSubscription.getKeys('auth'),
  },
};

// The above is the same output as:

const subscriptionObjectToo = JSON.stringify(pushSubscription);

หากต้องการส่งการสมัครใช้บริการจากหน้าเว็บ ให้ใช้โค้ดต่อไปนี้

function sendSubscriptionToBackEnd(subscription) {
  return fetch('/api/save-subscription/', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(subscription),
  })
    .then(function (response) {
      if (!response.ok) {
        throw new Error('Bad status code from server.');
      }

      return response.json();
    })
    .then(function (responseData) {
      if (!(responseData.data && responseData.data.success)) {
        throw new Error('Bad response from server.');
      }
    });
}

เซิร์ฟเวอร์ Node.js จะได้รับคำขอนี้และบันทึกข้อมูลลงในฐานข้อมูลเพื่อใช้ในภายหลัง

app.post('/api/save-subscription/', function (req, res) {
  if (!isValidSaveRequest(req, res)) {
    return;
  }

  return saveSubscriptionToDatabase(req.body)
    .then(function (subscriptionId) {
      res.setHeader('Content-Type', 'application/json');
      res.send(JSON.stringify({data: {success: true}}));
    })
    .catch(function (err) {
      res.status(500);
      res.setHeader('Content-Type', 'application/json');
      res.send(
        JSON.stringify({
          error: {
            id: 'unable-to-save-subscription',
            message:
              'The subscription was received but we were unable to save it to our database.',
          },
        }),
      );
    });
});

เมื่อมีรายละเอียด PushSubscription บนเซิร์ฟเวอร์ คุณจะส่งข้อความถึงผู้ใช้ได้ทุกเมื่อ

สมัครอีกครั้งเป็นประจำเพื่อป้องกันไม่ให้หมดอายุ

เมื่อสมัครรับข้อความ Push คุณมักจะได้รับ PushSubscription.expirationTime ของ null ในทางทฤษฎีแล้ว หมายความว่าการสมัครใช้บริการจะไม่มีวันหมดอายุ (ในทางตรงกันข้าม DOMHighResTimeStamp จะระบุเวลาหมดอายุที่แน่นอน) อย่างไรก็ตาม ในทางปฏิบัติแล้ว เบราว์เซอร์มักจะปล่อยให้การสมัครใช้บริการหมดอายุ ตัวอย่างเช่น กรณีนี้อาจเกิดขึ้นหากไม่ได้รับข้อความ Push เป็นเวลานาน หรือหากเบราว์เซอร์ตรวจพบว่าผู้ใช้ไม่ได้ใช้แอปที่มีสิทธิ์การแจ้งเตือน รูปแบบหนึ่งในการป้องกันปัญหานี้คือการให้ผู้ใช้สมัครรับข้อมูลอีกครั้งเมื่อได้รับการแจ้งเตือนแต่ละครั้ง ดังที่ข้อมูลโค้ดต่อไปนี้แสดง ซึ่งหมายความว่าคุณต้องส่งการแจ้งเตือนบ่อยพอที่จะป้องกันไม่ให้เบราว์เซอร์หมดอายุการสมัครใช้บริการโดยอัตโนมัติ คุณควรพิจารณาข้อดีและข้อเสียของความจำเป็นในการแจ้งเตือนที่ถูกต้องตามกฎหมายอย่างรอบคอบเทียบกับการส่งสแปมไปยังผู้ใช้โดยไม่สมัครใจเพียงเพื่อป้องกันไม่ให้การสมัครใช้บริการหมดอายุ ท้ายที่สุดแล้ว คุณไม่ควรพยายามหลบเลี่ยงความพยายามของเบราว์เซอร์ในการปกป้องผู้ใช้จากการสมัครรับการแจ้งเตือนที่ลืมไปนานแล้ว

/* In the Service Worker. */

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

  // Display notification or handle data
  // Example: show a notification
  const title = 'New Notification';
  const body = 'You have new updates!';
  const icon = '/images/icon.png';
  const tag = 'simple-push-demo-notification-tag';

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

  // Attempt to resubscribe after receiving a notification
  event.waitUntil(resubscribeToPush());
});

function resubscribeToPush() {
  return self.registration.pushManager.getSubscription()
    .then(function(subscription) {
      if (subscription) {
        return subscription.unsubscribe();
      }
    })
    .then(function() {
      return self.registration.pushManager.subscribe({
        userVisibleOnly: true,
        applicationServerKey: urlBase64ToUint8Array('YOUR_PUBLIC_VAPID_KEY_HERE')
      });
    })
    .then(function(subscription) {
      console.log('Resubscribed to push notifications:', subscription);
      // Optionally, send new subscription details to your server
    })
    .catch(function(error) {
      console.error('Failed to resubscribe:', error);
    });
}

คำถามที่พบบ่อย

คำถามที่พบบ่อยมีดังนี้

คุณเปลี่ยนบริการพุชที่เบราว์เซอร์ใช้ได้ไหม

ไม่ เบราว์เซอร์จะเลือกบริการพุช ตามที่เอกสารนี้กล่าวถึงในการเรียก subscribe() เบราว์เซอร์จะส่งคำขอเครือข่ายไปยังบริการพุชเพื่อดึงรายละเอียดที่ประกอบขึ้นเป็น PushSubscription

บริการพุชที่แตกต่างกันใช้ API ที่แตกต่างกันไหม

บริการพุชทั้งหมดคาดหวัง API เดียวกัน

API ทั่วไปนี้เรียกว่า Web Push Protocol ซึ่งอธิบายคำขอเครือข่ายที่แอปพลิเคชันของคุณสร้างขึ้นเพื่อทริกเกอร์ข้อความ Push

หากคุณติดตามผู้ใช้บนเดสก์ท็อป ผู้ใช้รายนั้นจะได้รับการติดตามบนโทรศัพท์ด้วยไหม

ไม่ ผู้ใช้ต้องลงทะเบียนรับข้อความ Push ในแต่ละเบราว์เซอร์ที่ต้องการรับข้อความ นอกจากนี้ ผู้ใช้ยังต้องให้สิทธิ์ในอุปกรณ์แต่ละเครื่องด้วย

ขั้นตอนถัดไป

Codelabs