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
- 生成密钥后,请确保在你的前端,在src/js/pushpi.js 中的configurePushSubscription()函数中替换 公钥。
- 还有,你要在服务器端替换公钥和私钥,在 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中,代码已经在等待我们接收推送订阅,并将其提交到一个名为subscriptionsDb的node-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。