在JavaScript中使用PWA推送通知的12个步骤

1,853 阅读7分钟

PWA推送通知在JavaScript中?是的,你可以在12个步骤中做到!

推送通知是本地应用程序的特权,但现在可以直接发送到PWA上,本教程讨论了如何用12个步骤实现推送API

简介

直到最近,推送通知还是原生应用的特权,现在这种情况已经改变。 推送通知现在可以直接发送到PWA上:就像本地应用一样,浏览器不必打开,甚至在后台也不必。

本教程讨论了如何在12个步骤中实现推送API。我们将这个API添加到现有的PWA中,用于创建 "自拍"(从我的个人资料中访问我以前的教程)。

项目设置

作为本教程的起点,克隆以下GitHub仓库:

Shell

git clone https://github.com/petereijgermans11/progressive-web-app 

接下来,在你的终端,转到目录。

Shell

 cd progressive-web-app

 cd pwa-article/pwa-app-native-features-push-api-init

用以下方法安装依赖项。

使用Shell

npm i && npm start 

打开网络应用:http://localhost:8080/index.html

用JavaScript推送API

网络推送通知的流程

网络推送通知是一个涉及4个角色的协议(图片1)

  • 用户:这是想接收通知的人
  • 应用程序或PWA:它在浏览器中运行。使用推送API的浏览器包含一个推送服务,负责将推送通知从服务器传送给用户
  • 服务工作者:它在应用程序、浏览器和网络之间充当代理服务器
  • 推送服务器或服务器:它通过推送服务将推送通知发送给服务工作器

1. 当应用程序询问用户是否允许接收推送通知时,流程就开始了。

2. 一旦用户给予许可,应用程序就会 注册一个服务工作器

3.- 6. 当PWA收到来自服务工作器的注册时,PWA可以用它来创建一个推送订阅。 A 推送服务也需要创建一个推送订阅。推送订阅包含一个推送服务的端点来发送推送通知,也是如此。

7. 在这一点上,应用程序将创建的推送订阅发送给服务器。服务器需要推送订阅的端点来发送推送通知。

8. 当服务器收到推送订阅时,它被存储在一个叫做subscriptionsDB的数据库中。

9. 服务器从推送订阅中向端点发送推送通知。然后,推送通知通过推送服务被路由到服务工作器服务工作器监听推送通知。 push-event.

10. 然后,服务工作者将推送通知转发给用户。

11. 11.当用户点击推送通知时,服务工作器通过通知点击事件来接收它。

12. 12.服务工作者现在几乎可以对推送通知做任何他想做的事情。

现在你知道了这个流程,是时候进入真正的实施了。

步骤1和2:用户权限

在你向用户发送推送通知之前,你必须通过显示一个提示来征求该用户的许可。为了让这个提示开始,将下面的代码添加到现有的文件中:src/js/pushpi.js(清单1)。

src/js/pushapi.js

JavaScript

const enableNotificationsButtons = document.querySelectorAll('.enable-notifications'); 

const askForNotificationPermission = () => { 
      Notification.requestPermission(result => { 
      if (result === 'granted') { 
          displayConfirmNotification();
          // configurePushSubscription(); 
      } 
   }); 
}; 

if ('Notification' in window) {
      for (let i = 0; i < enableNotificationsButtons.length; i++) { 
          enableNotificationsButtons[i].style.display = 'inline-block'; 
          enableNotificationsButtons[i].addEventListener('click', askForNotificationPermission); 
      } 
} 

...

清单1

将下面的代码放在 "推送服务 "的底部,以便我们能够使用推送服务。 src/index.html这样我们就可以使用pushapi.js(清单2)

JavaScript

<script src="src/js/pushapi.js"></script>

清单2

在我们现有的PWA(图片2)中,当点击 "启用通知 "按钮时,我们会向用户征求许可。 只有在浏览器支持推送通知的情况下,该按钮才应该是可见的!在代码中,你可以通过条件来识别这个检查。"if ('Notification' in window)".

src/css/app.css中添加以下内容(清单3):

CSS

.enable-notifications { 
  display: none; 
} 

清单3

显示一个通知

作为第一步,当我们获得许可时,我们向用户显示一个通知(有一个好的/取消的按钮)(清单4)

将这段代码添加到 src/js/pushapi.js

JavaScript

const displayConfirmNotification = () => { 
     if ('serviceWorker' in navigator) { 
        const options = {
              body: 'You successfully subscribed to our Notification service!',
              icon: 'src/images/icons/app-icon-96x96.png',
              image: 'src/images/main-image-sm.jpg',
              dir: 'ltr',
              lang: 'en-US',
              badge: 'src/images/icons/app-icon-96x96.png',
              tag: 'confirm-notification',
              actions: [ 
                 {
                      action: 'confirm',
                      title: 'Okay',
                      icon: 'src/images/icons/app-icon-96x96.png' 
                  }, 
                  {
                      action: 'cancel',
                      title: 'Cancel',
                      icon: 'src/images/icons/app-icon-96x96.png' 
                    
                  } 
              ] 
       }; 
       navigator.serviceWorker.ready 
         .then(sw => sw.showNotification('Successfully subscribed!', options));
     } 
}; 


...

清单4

该 navigator.serviceWorker.ready...检查服务工作器是否被激活。另外,通过函数sw.showNotification(),显示了一个Notification。

步骤3和4:注册服务工作器

注册和激活服务工作器已经在我的第一个PWA教程中介绍过了。

步骤5:订阅推送通知

要向用户订阅推送通知,需要两个步骤:

  • 首先,获得用户同意(步骤1和2)
  • 通过推送服务获得推送订阅(第5步)

什么是推送服务?

  • 每个浏览器都通过自己的系统,即所谓的 "推送服务 "来管理推送通知。
  • 当用户给予推送通知的权限时,应用程序就能订阅浏览器的推送服务。
  • 这将创建一个特殊的推送订阅,其中包含推送服务的 "端点URL",每个浏览器的端点URL都不同(清单5)。
  • 在第9步中,你的推送通知会被发送到这些URL,并用公钥进行加密。
  • 推送服务确保推送通知被发送到正确的客户端。
{
  'endpoint': 'https://SOME.PUSHSERVICE.COM/SOMETHING-UNIQUE', 
  'keys': {
	'p256dh': 'BGhFV5qx5cdOaD_XF293OqMdYSUIrMrzj2-RuzGwOTIhdW8v’, 
	'auth': 'HA1JEiRAp2HLuVH639Oumw'
  } 
}; 

...

清单5

端点是推送服务的URL。服务器使用这个端点来发送推送通知(步骤9)。密钥对象包含用于加密通知的值。

推送服务如何知道要将推送通知发送给哪个客户端?

端点URL包含一个唯一的标识符。这个标识被推送服务用来将收到的推送通知发送到正确的设备上。当通知被浏览器处理时,它被确定为哪个服务工作器(步骤10)应该通过一个 Push-event.

应用服务器密钥

在将用户订阅到推送通知之前,你必须生成一组 "applicationServer Keys"。应用服务器密钥,也被称为VAPID密钥,对服务器来说是独一无二的。 它们使推送服务能够知道用户订阅了哪个服务器。这些密钥确保向该用户发送推送通知的是同一个服务器。

配置推送订阅

清单6向你展示了如何配置一个推送订阅以及如何将这个PushSubscription发送到服务器。

注意!

要激活下面的功能(清单6),你需要:

1.激活askForNotificationPermission()函数(清单1)中的configurePushSubscription()

2.另外移除displayConfirmNotification()函数的调用

在src/js/pushapi.js中添加

JavaScript

const configurePushSubscription = () => {
   if ('serviceWorker' in navigator && "PushManager" in window) {
       let serviceWorkerRegistration;
        // Service worker registratie (step 4)
       navigator.serviceWorker.ready
           .then(registration => {
               serviceWorkerRegistration = registration;
               return registration.pushManager.getSubscription();
           })
           .then(subscription => {
               if (subscription === null) {
                   // Create a new Push Subscription (step 5 and 6)
                   return serviceWorkerRegistration.pushManager.subscribe({
                       userVisibleOnly: true,
                       applicationServerKey: urlBase64ToUint8Array(
                            'BPg36y0YwKrMOgutw18ZeX9Ps3fBy5tNnA_OdPIor’
                       )
                   });
               }
           })
            // Verzenden Push Subscription naar de server (step 7)
           .then(pushSubscription => {
               return fetch(`${SERVER_URL}/subscriptions`, {
                   method: 'POST',
                   headers: {
                       'Content-Type': 'application/json',
                       'Accept': 'application/json'
                   },
                   body: JSON.stringify(pushSubscription)
               });
           })
           .then(response => {
               if (response.ok) {
                   displayConfirmNotification();
               }
           })
           .catch(error => console.log(error));
   }
};

....

清单6

首先,上述代码检查浏览器是否支持推送通知和服务工作器,使用的条件是:if ('serviceWorker' in navigator && "PushManager" in window) {}

如果服务工作器被注册并激活(navigator.serviceWorker.ready...),我们通过调用:registration.pushManager.getSubscription()来检查是否有推送订阅存在。

如果它是空的,我们调用registration.pushManager.subscribe()来通过推送服务获得一个新的推送订阅。为此,输入applicationServerKey。

如何创建应用服务器密钥

你可以从服务器根部创建一个公共和私有的applicationServerKeys集合。要做到这一点,首先克隆 服务器通过。

Shell

git clone https://github.com/petereijgermans11/progressive-web-app-server 

进入到 根文件夹这个服务器,通过终端运行下面的命令来生成密钥。

Shell

npm i && npm run web-push 
  1. 生成密钥后,请确保在你的前端,在src/js/pushpi.js 中的configurePushSubscription()函数中替换 公钥
  2. 还有,你要在服务器端替换公钥和私钥,在 routes/routes.js文件(清单7)。

JavaScript

const VAPID_PUBLIC_KEY = 'plak hier je public key'; 

const VAPID_PRIVATE_KEY = 'plak hier je private key'; 

webpush.setVapidDetails(VAPID_MAIL, VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY); 

...

清单7

步骤6和7:将推送订阅发送给服务器

一旦你为用户订阅了推送通知,并且收到了来自的推送订阅推送服务,推送订阅就会被发送到服务器上(清单6)。最后,在服务器上,你把这个推送订阅存储在一个 subscriptionsDb数据库中。

步骤8:在服务器上接收推送订阅信息

在前面的步骤中,你已经克隆了服务器。

然后在你的终端中进入这个服务器的根目录,并安装好依赖关系,用以下方式启动服务器。

Shell

npm i && npm start

该服务器运行在localhost:3000上。

progressive-web-app-server/routes/routes.js中,代码已经在等待我们接收推送订阅,并将其提交到一个名为subscriptionsDbnode-json-db中。这是一个简单的数据库,用于存储JSON文件中的信息。推送订阅是通过POST URL`/subscriptions`进来的(列表8)。

JavaScript

app.post('/subscriptions', (req, res) => { 

  const subscription = req.fields; 

  subscription.id = uuid.v4(); 

  subscriptionsDb.push(`subscriptions/${subscription.id}`, subscription, false); 

  res.status(200).send('subscription saved'); 
}); 

...

清单8

步骤9:用网络推送向用户发送推送通知

从现在开始,我们可以向用户发送推送通知。在我们的例子中,一个推送通知会通过 webpush API当服务器上收到一张*"自拍 "* 时,就会向相关用户发送推送通知。如何用你的PWA发送 "自拍",在我以前的教程中已有描述。

route.js中的预存代码。

JavaScript

 app.post('/selfies', (req, res) => {
   const post = {title: req.fields.title, location: req.fields.location};
   const selfieFileName = path.basename(req.files.selfie.path);
   post.selfieUrl = `${req.protocol}://${req.get('host')}/images/${selfieFileName}`;
   post.id = req.fields.id;

   selfiesDb.push(`selfies/${post.id}`, post, false);

   const subscriptions = subscriptionsDb.getData('/');
   Object.values(subscriptions).forEach(subscription => {
     if (subscription.endpoint && subscription) {
        webpush.sendNotification(subscription, JSON.stringify({
         title: 'New Selfie Added!',
         content: `${post.title} @ ${post.location}`,
         imageUrl: post.selfieUrl,
         openUrl: 'help'
     })).catch(error => console.log(error));
   }
 });
 res.status(200).send({message: 'Selfie stored', id: post.id});
});

...

清单9

在上述代码中(清单9),发送的 "Selfies "通过POST URL '/selfies' 到达。

这些 "自拍 "被存储在一个名为 "自拍 "的节点-js-db中。 selfiesDb.然后使用subscriptionsDb.getData('/')subscriptionsDb删除订阅。最后,对于每一个找到的订阅,都会发送一个推送通知,内容为 webpush.sendNotification().

步骤10: 通过服务工作器接收推送通知

为了以用户身份接收推送通知,我们需要在我们的服务工作器中添加以下代码(清单10)

将这段代码添加到现有的 sw.js:

JavaScript

self.addEventListener('push', event => {
  const data = JSON.parse(event.data.text());
   const options = {
       body: data.content,
       icon: 'src/images/icons/app-icon-96x96.png',
       badge: 'src/images/icons/app-icon-96x96.png',
       data: {
           url: data.openUrl
       }
   };
   event.waitUntil(
       self.registration.showNotification(data.title, options)
   );
});

...

清单10

上面的代码监听的是 Push-event并读取从服务器发送的数据的有效载荷。有了这个有效载荷数据,你就可以用*self.registration.showNotification()*在浏览器中显示一个推送通知(图片3)。 图片3

测试

为了测试推送通知,你需要通过你的PWA发送一张 "自拍"。这当然可以通过localhost:8080来完成。

然而,如果你想在你的手机或平板电脑上测试,你可以使用 ngrok来获取一个公共URL

使用以下方法安装ngrok

Shell

npm install -g ngrok.

为什么你没有收到推送通知?

  • 在你的浏览器中启用推送通知。
  • 在发送 "自拍 "之前,你必须点击 "启用通知 "按钮(图片2)。点击授予权限。
  • applicationServer Keys没有设置。
  • 只有在localhost下:通过你的(Chrome)开发工具手动 "取消注册 "你的服务工作器,并重新加载你的PWA。

最后

在你完成上述步骤后,你仍然需要实现第11和12步。这些步骤已经在最终版本中实现:pwa-app-native-features-push-api-final。