webpush
Webpush协议:
W3c规范 https://www.w3.org/TR/push-api/
1.浏览器订阅推送
2.上传token
3.发送推送
4.浏览器厂商推送服务器根据浏览器状态,缓存或发送推送消息。
原生浏览器接入方式存在部分局限性:
ios 不支持webpush ,safri使用私有的api,各大厂商推送中心差异化,推送消息展示差异
原生方式使用webpush:
使用命令行生成您的秘钥,导入密钥时去除任何的换行符
1.生成VAPID秘钥:
openssl ecparam -name prime256v1 -genkey -noout -out vapid_private.pem
2.创建密钥DER形式base64编码:
openssl ec -in ./vapid_private.pem -outform DER|tail -c +8|head -c 32|base64|tr -d '=' |tr '/+' '_-' >> private_key.txt
openssl ec -in ./vapid_private.pem -pubout -outform DER|tail -c 65|base64|tr -d '=' |tr '/+' '_-' >> public_key.txt
端侧js:
function urlB64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
navigator.serviceWorker.getRegistration('sw.js').then(function (sw) {
if(sw){ // 这里为方便测试每次刷重新订阅
sw.unregister().then(function () {
swRegister()
})
}else{
swRegister()
}
})
function swRegister() {
navigator.serviceWorker.register('sw.js')
.then(function (sw) {
sw.pushManager.getSubscription().then(function (sub) {
if (!sub) {
subNew(sw)
} else {
sub.unsubscribe().then(function(successful) {
subNew(sw)
}).catch(function(e) {
})
}
})
})
}
function subNew(sw) {
var key = urlB64ToUint8Array('生成的公钥');
sw.pushManager.subscribe({
applicationServerKey: key,
userVisibleOnly: true,
}).then(function (sub) {
// sub包含后面需要使用的endpoint 秘钥信息
}).catch(function (e) {
});
}
服务端java demo:
使用lib:https://github.com/web-push-libs/web-push
提供python nodejs java
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); //添加密码库
PushService pushService = new PushService(上步生成的秘钥信息);
Notification nc = new Notification("浏览器订阅endpoint",
"浏览器订阅p256dh","浏览器订阅auth"),"消息内容");
HttpResponse r = pushService.send(nc);
返回消息中的http statuscode为消息发送结果:
详细含义参照:
https://autopush.readthedocs.io/en/latest/http.html#push-service-http-api
errorcode 部分
使用huawei 华为Push推送接入webpush;
huawei 提供了对端侧js和云侧发送接口的封装,可以和发送android消息一样的形式发送web消息,不用关心原生endpoint 秘钥等信息:
参照华为开发者联盟接入webpush,这里web推送目前是挂在android应用下。
https://developer.huawei.com/consumer/cn/doc/development/HMS-Guides/push-webpush
这里编写了一个demo:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<script src="https://push-static.dbankcdn.com/hms-messaging.js"></script>
<input type="button" id="tk" value="getToken">
<input type="button" id="tkdel" value="delToken"> <br>
<p id="tkv">token:</p>
<script>
var cf = {
apiKey: "{{apikey}}",
appId: "{{appid}}",
};
hms.initializeApp(cf);
var msg = hms.messaging();
msg.usePublicVapidKey("{{pubkey}}");
msg.onMessage((payload) => {
console.log('Message received.', payload);
// alert('Message received.', payload);
});
var tkv = '';
function getTk() {
msg.getToken().then((currentToken) => {
if (currentToken) {
console.log('getToken succ: ', currentToken);
$('#tkv').text("token: " + currentToken)
tkv = currentToken;
// alert('getToken Success.');
} else {
console.log('拿不到token');
}
}).catch((err) => {
console.log( err.message);
});
}
$("#tkdel").on("click", function () {
if(tkv!=''){
msg.deleteToken(tkv).then(function (r) {
console.log(r?'删除ok:':'删除失败')
});
}
});
$("#tk").on("click", function () {
Notification.requestPermission().then((permission) => {
if (permission === 'granted') {
console.log('granted');
getTk()
} else {
console.log('拒绝推送 ' + permission);
}
})
})
navigator.serviceWorker.register("/webpush/sw.js", {
scope: "/"
}).then((reg) => {
console.log('register sw.js success');
msg.useServiceWorker(reg);
})
</script>
</body>
</html>
在/webpush/sw.js 提供后台servicework处理js:处理后台消息,不设置默认将通知消息弹出,数据类消息丢弃,设置后应自行处理通知类消息弹出。
importScripts('https://push-static.dbankcdn.com/hms-messaging.js');
var cf = {
apiKey: "{{apikey}}",
appId: "{{appid}}",
};
// Initialize hmsConfig
hms.initializeApp(cf);
var msg = hms.messaging();
msg.setBackgroundMessageHandler(function (d) {
console.log('[sw.js] Received background msg ', d);
// data consumer here
// return self.registration.showNotification(notificationTitle,
// notificationOptions);
});
获取到token之后应该存储到自己的服务器
云侧发送使用华为push sdk:
按照接口文档发送即可:
https://developer.huawei.com/consumer/cn/doc/development/HMS-References/push-sendapi