前言
手机推送功能是比较常见的需求,由于墙的原因浏览器推送宛如鸡肋,最近公司业务需要面向海外市场,所以计划给网页添加推送功能。
手机 app 推送国内有很多的推送厂商可以选择(ex:JPush),但是浏览器推送由于大环境影响基本没有类似产品,只能手撸(听说 JPush 正在着手浏览器推送,很是期待)。听说我司的产品(iOS、Android app)使用极光推送已经 3 年了,为什么是听说,因为我才入职两年,手动 [捂脸]。
本文将主要介绍两种网页推送,要求网页支持 HTTPS。
支持 Push Api 的浏览器
现在主流的现代浏览器都支持 Web Push API ,web push 允许浏览器打开的时候接收到推送(就算页面被关闭也能接受)。
Push APi 要求网页支持 HTTPS,因为 Push API 使用 Service Work 只能在 HTTPS 网站上使用,但是如果测试的话可以直接使用 localhost 也是允许的。
Push APi 推送的全流程如下图所示:
浏览器通过如下代码完成:
// https://example.com/webapp.js
navigator.serviceWorker.register('serviceworker.js').then(
function(serviceWorkerRegistration) {
serviceWorkerRegistration.pushManager.subscribe().then(
function(pushSubscription) {
console.log(pushSubscription.endpoint);
console.log(pushSubscription.getKey('p256dh'));
console.log(pushSubscription.getKey('auth'));
// The push subscription details needed by the application
// server are now available, and can be sent to it using,
// for example, an XMLHttpRequest.
}, function(error) {
// During development it often helps to log errors to the
// console. In a production environment it might make sense to
// also report information about errors back to the
// application server.
console.log(error);
}
);
});
我们需要注册一个 ServiceWork,成功注册后会得到一个 serviceWorkerRegistration,可以使用 serviceWorkerRegistration.pushManager.subscribe
这个方法来订阅推送成功订阅后返回 pushSubscription 用于标识当前当前的网页用户,需要传到自己的应用服务中用于推送。注意现在是能收到推送,但是不发触发通知,我们可以在 servicework.js 文件中添加 通知逻辑:
self.addEventListener('push', function(event) {
console.log('[Service Worker] Push Received.');
console.log(`[Service Worker] Push had this data: "${event.data.text()}"`);
const title = 'Push Codelab';
const options = {
body: 'Yay it works.',
icon: 'images/icon.png',
badge: 'images/badge.png'
};
event.waitUntil(self.registration.showNotification(title, options));
});
服务端等到 pushSubscription 后可以通过里面的参数 auth 和 p256dh 给 endpoint 发送推送请求。
到此支持 Push Api 浏览推送就到此结束。
Safari 的 APNs 推送
Safari 的没有支持 Push Api 功能,但 OS X v10.9 之后可以使用 APNs 服务来支持推送功能,且功能更强大,允许 Safari 在关闭的情况下接受推送通知。
safari apns 要求网页支持 HTTPS,不然无法请求推送,本地测试的话可以使用自建证书来测试。
Safari 推送和手机应用推送都走的 APNS 通道,由于公司的手机 APP 已经支持了推送,后台使用 token 做验证,所以后台基本不需要修改推送逻辑,非常的简单。
注册 Website Push IDs
首先需要在 Certificates, Identifiers & Profiles
中注册 Website Push IDs
构建 Push Package
当 Safari 请求推送权限的时候,Safari 会向自己的服务器请求 Push Package,如果请求失败会返回错误,所以我们需要先创建这个 Push Package。
Push Package 最终要包含如下文件
BayAirlines.pushpackage/
icon.iconset/
icon_16x16.png
icon_16x16@2x.png
icon_32x32.png
icon_32x32@2x.png
icon_128x128.png
icon_128x128@2x.png
manifest.json
signature
website.json
icon.iconset/ 里面包含了推送所需的 icon。
website.json 主要包含网页信息。
Manifest.json 会记录所有的文件的 hash 值。大概长这样
{
"website.json": {
"hashType": "sha512",
"hashValue": "4309a0cf6ee37909423fb4f5f762eb530d4a7cfe9e1d30b9c85b602afb9296a508f5df00c6f63439e4dcc4484aae4cd77d1f632678ece0ef1b62ca6c9cbdebb3"
},
"icon.iconset/icon_16x16.png": {
"hashType": "sha512",
"hashValue": "8bb462e25ca79cca241355f5ae97ffab352acf7d2a0390f6547f1d0a55ade59e01e725bea70778ad2822b1ec137a8c0547197727ae2e9fed620b0d3ddea6803b"
},
...
}
幸运的是 Apple 提供了一个工具让我们很方便的生成 website.json 和 signature 这两个文件, 我们只需要准备好 icon.iconset/ 和 website.json 即可。createPushPackage.php 我们会得到 PushPackage 文件。
此时我们还需要给自己的应用服务添加一个 API,返回刚刚生成的 PushPackage 文件。
webServiceURL/version/pushPackages/websitePushID
请求权限
请求推送权限的流程可以整理成下图所示:
- 调用
window.safari.pushNotification.permission("< 你的 应用 id>")
可以获得当前的应用权限,如果当前权限为 default 则表示之前没有请求过。可以调用
window.safari.pushNotification.requestPermission(
'The web service URL.', //
'The Website Push ID.', //
{}, // Data that you choose to send to your server to help you identify the user.
function () { } // 请求结果回调
);
注意调用 requestPermission 时,safari 回去获取 push package 这个文件,如果之前的不步骤没有完成这里会失败。如果成功则会弹框提醒用户是否要运行当前网站接收推送通知。
用户同意后可以通过 window.safari.pushNotification.permission("< 你的 应用 id>")
方法获得 permission object,permission. deviceToken 需要传到自己服务器用于给 APNS 发送推送请求。到此 safari 推送已经完成。
Safari 推送和 iOS app 推送都是走的 APNS 服务,由于之前应用(react native 应用)已经集成了推送功能使用 jpush-react-native 这个插件,而且使用 token 的验证方式,所有服务端那边需要修改的东西比较少,只需要修改web 应用的 keyId 即可。
done!
PS:为了极光征文大赛才注册的简书,平常文章都是放 GitHub 的,希望下次活动可以支持 Github 上的文章。
「本文为极光征文参赛文章」