HTML5+ push消息推送
- push消息推送
- 关键 API 介绍
- plus.push
- addEventListener
- clear
- createMessage
- getAllMessage
- getClientInfo
- setAutoNotification
- remove
- 实践
- 消息推送
- 开启权限
push消息推送
HTML5+ 的 Push 消息推送功能是一个强大的特性,它允许开发者在 Web 应用中实现服务端向客户端主动推送消息的能力。这种机制对于提升用户体验、实现实时通信等场景非常有用。
HTML5+ 是对 HTML5 标准的扩展,它提供了一系列增强的 API 以支持更丰富的 Web 应用功能。Push 消息推送是其中之一,它允许开发者通过特定的 API 接收来自服务端的消息,并在客户端进行展示或处理。
关键 API 介绍
plus.push
plus.push 是 HTML5+ 中用于管理推送消息的主要对象。通过它,开发者可以添加事件监听器、清空推送消息、创建本地消息、获取所有推送消息、获取客户端推送标识信息等。
addEventListener
addEventListener:添加推送消息事件监听器,支持的事件类型包括“click”(用户点击推送消息)、“receive”(应用接收到推送消息)等。
void plus.push.addEventListener( type, listener, Boolean );
- type: ( String ) 必选 事件类型
支持事件类型:“click”-从系统消息中心点击消息启动应用事件;“receive”-应用从推送服务器接收到推送消息事件。 - listener: ( PushReceiveCallback ) 必选 事件监听器回调函数,在接收到推送消息时调用
- capture: ( Boolean ) 可选 是否捕获事件,此处可忽略
clear
clear:清空所有推送消息,包括系统消息中心中的推送消息。
void plus.push.clear();
createMessage
createMessage:在本地创建推送消息,并添加到系统消息中心。
void plus.push.createMessage( content, payload, option );
参数:
- content: ( String ) 必选
消息显示的内容,在系统通知中心中显示的文本内容。 - payload: ( String | Object ) 可选
消息承载的数据,可根据业务逻辑自定义数据格式。 - options: ( MessageOptions ) 可选
创建消息的额外参数,参考MessageOptions。
返回值:
void : 无
getAllMessage
getAllMessage:获取客户端接收到的所有推送消息。 仅包括在系统消息中心显示的推送消息,不包括调用setAutoNotification(false)方法设置不显示推送消息后接收到的消息。
PushMessage[] plus.push.getAllMessage();
返回值:
PushMessage : Array[PushMessage]对象,推送消息PushMessage数组。
getClientInfo
getClientInfo:获取客户端的推送标识信息,如设备令牌(token)、推送服务令牌(clientid)等。
客户端标识信息用于业务服务器下发推送消息时提交给推送服务器的数据,用于说明下发推送消息的接收者(客户端)。 通常需要客户端在第一次运行时获取并提交到业务服务器绑定。
ClientInfo plus.push.getClientInfo();
返回值:
ClientInfo : 客户端推送标识信息对象
setAutoNotification
setAutoNotification:设置程序是否将接收到的推送消息显示在系统消息中心。
默认情况下程序在接收到推送消息后将会在系统消息中心显示,通过此方法可关闭默认行为,
接收到推送消息后不在系统消息中心显示,通过addEventListener方法的“receive”事件监听处理接收到的消息。
在这种模式下可通过createMessage方法创建在系统消息中心显示的消息。
void plus.push.setAutoNotification( notify );
参数:
notify: ( Boolean ) 必选 是否自动提示推送消息
可取值true或false,true表示自动显示推送消息,false则不显示。默认值为true。
返回值:
void : 无
remove
remove:删除指定的推送消息,但 iOS 平台不支持对单条消息的删除操作。
删除系统消息中心指定的推送消息,可通过getAllMessage方法获取所有的消息后进行操作。
void plus.push.remove( message )
参数:
message: ( PushMessage ) 必选 要删除的消息对象,可通过getAllMessage()方法来获取消息。
返回值:
void : 无
实践
消息推送代码在onLaunch生命周期中监听
onLaunch: function() {
isAppLunched = false
// asyncClientInfo()
getUserInfoAsync({
connectSocket: true
}).then(() => {
setTimeout(() => {
initPlusListener() //消息推送
initPlusPermissions() //通知权限
isAppLunched = true
}, 1000)
})
},
消息推送
export const initPlusListener = () => {
plus.push.setAutoNotification(true) //设置了推送消息的自动通知功能
// ios端 存在点击异常: https://ask.dcloud.net.cn/question/135753
plus.push.addEventListener('receive', (msg) => {
try {
//
handleAppNoticeReceive(msg)//处理接收到的消息
} catch (error) {
track( 'appMsgNoticeReceive', { msg, desc: '处理出错' })
}
}, false)
plus.push.addEventListener('click', (msg) => {
try {
//当用户点击通知栏中的推送消息时,会触发这个事件。
//在事件处理函数中,调用 handleAppNoticeClick 函数来处理点击事件。
handleAppNoticeClick(msg)
} catch (error) {
track('appMsgNoticeClick', { msg, desc: '处理出错' })
}
}, false)
}
//收到透传消息
//只有APP在线时,才会触发receive事件,透传消息不会触发系统消息,需要创建本地消息
const handleAppNoticeReceive = (rawMsg) => {
let msgPayload = {}
log.info('[handleAppNoticeReceive] 收到推送消息 ', JSON.stringify(rawMsg))
track( 'appMsgNoticeReceive', { rawMsg, desc: '收到推送消息' })
//尝试解析消息rawMsg.payload赋给msgPayload
try {
if (typeof rawMsg.payload === 'string') { //如果是字符串
msgPayload = JSON.parse(rawMsg.payload)
} else if(isPlainObject(rawMsg.payload)) { //如果是object对象
msgPayload = rawMsg.payload
}
} catch(e) {
const desc = '解析 app 消息 msg.payload 异常'
track( 'appMsgNoticeReceive', { rawMsg, desc })
log.error(desc, e)
return
}
//从 msgPayload 中提取 data 字段,并解构出 id, shortMessage, title, type。
const msgData = get(msgPayload,'data') || msgPayload || {}
const { id, shortMessage, title, type } = msgData
//验证 id 和 type 是否存在,以及 shortMessage 和 title 是否为空。如果验证失败,记录错误并返回。
if (isUndefined(id) || isUndefined(type)) {
const desc = '消息携带 data 数据中 id,type 异常'
log.error(desc, msgData)
track( 'appMsgNoticeReceive', { msgData, desc })
return
}
if (!shortMessage || !title) {
const desc = '消息携带 data 数据中 shortMessage,title 异常'
log.error(desc, msgData)
track( 'appMsgNoticeReceive', { msgData, desc })
return
}
//记录解析成功的消息数据
track( 'appMsgNoticeReceive', {
msgData,
desc: '解析 msgPayload.data 数据'
})
log.info('解析 msgPayload.data 数据', msgData)
// TODO: 不本地创建消息,可能存在BUG 推送太多。
// plus.push.createMessage(shortMessage, rawMsg.payload, {title});
// setAppBadgeNum('message', 1);
}
//消息点击事件
//【APP在线】,收到透传消息通过,不会提醒至通知栏目,需要发送本地消息,再进行点击触发的点击事件。
//【APP离线】,收到离线透传消息,必须通过Java后台的Intent字符串携带payload,且符合格式才能触发click事件,格式不符合不会触发
const handleAppNoticeClick = (rawMsg) => {
//日志记录和跟踪
log.info('[handleAppNoticeClick] 点击推送消息 ', JSON.stringify(rawMsg))
track( 'appMsgNoticeClick', { rawMsg, desc: '点击推送消息' })
//尝试解析 rawMsg.payload,如果解析失败则记录错误并返回。
let msgPayload = {}
try {
if (typeof rawMsg.payload === 'string') {
msgPayload = JSON.parse(rawMsg.payload)
} else if(isPlainObject(rawMsg.payload)) {
msgPayload = rawMsg.payload
}
} catch(e) {
const desc = '解析 app 消息 msg.payload 异常'
track( 'appMsgNoticeClick', { rawMsg, desc })
// 解析 app 消息 msg.payload 异常
log.error(desc, e)
return
}
//从 msgPayload 中提取 data 字段,并解构出 ext, id, type, orgId, orgName。
const msgData = get(msgPayload,'data') || msgPayload || {}
const { ext, id, type, orgId = '', orgName = ''} = msgData
//验证 id 和 type 是否存在。如果验证失败,记录错误并返回。
if (isUndefined(id) || isUndefined(type)) {
const desc = '消息携带 data 数据中 id,type 异常'
log.error(desc, msgData)
track( 'appMsgNoticeClick', { msgData, desc })
return
}
//记录解析成功的消息数据
track( 'appMsgNoticeClick', {
msgData,
desc: '解析 msgPayload.data 数据'
})
log.info('解析 msgPayload.data 数据', msgData)
//解析 ext 字段,如果解析失败则记录错误并返回。(ext是从传递进来的参数里解析出来的数据)
let extInfo = {}
if (typeof ext === 'string' && ext !== '' && ext !== 'null') {
try {
extInfo = JSON.parse(ext) // TODO: 提取逻辑
} catch(e) {
// 解析 消息数据中 ext 信息异常
const desc = '解析 消息数据中 ext 信息异常'
log.error(desc, e)
track('appMsgNoticeClick', {ext, desc })
return
}
}
//根据 type(根据传递进来的参数解析出来的) 的值进行不同的页面导航,并记录相应的跟踪信息。
let routeData = {}
switch (type == 0) {
case 0:
routeData = {id,orgId,orgName}
track( 'appMsgNoticeClick', { desc: '进入 bjjk', routeData })
navToPage('console.alarm.detail', routeData)
break
case 1:
routeData = {
id,
orgId,
orgName,
title: extInfo.modelName,
...extInfo,
}
track( 'appMsgNoticeClick', { desc: '进入 mxjk', routeData })
navToPage('console.model.detail', routeData)
break
case 2:
if (extInfo.isBatch) {
track( 'appMsgNoticeClick', { desc: 'gd列表' })
navToPage('console.work.orgList')
return
}
routeData = {
orgId,
info: {
status: extInfo.status || 0,
id: extInfo.ticketId,
type: extInfo.ticketType
}
}
track( 'appMsgNoticeClick', { desc: '进入 gd详情', routeData })
navToPage('console.work.workDetail', routeData)
break
}
}
开启权限
export const initPlusPermissions = () => {
try {
plus.screen.lockOrientation('portrait-primary') //竖屏正方向锁定
handleNoticePermission()
} catch (error) {
log.error('initPlusPermissions error', error)
//
}
}
const handleNoticePermission = () => {
let type = uni.getSystemInfoSync().platform
if (type === 'android') {
var main = plus.android.runtimeMainActivity();
var pkName = main.getPackageName();
var NotificationManagerCompat = plus.android.importClass(
"android.support.v4.app.NotificationManagerCompat");
if (NotificationManagerCompat == null) {
NotificationManagerCompat = plus.android.importClass(
'androidx.core.app.NotificationManagerCompat');
}
var packageNames = NotificationManagerCompat.from(main);
if (!packageNames.areNotificationsEnabled()) { //手机没有开启通知的权限
uni.showModal({
title: '通知管理',
content: '是否允许消息推送',
success: function(res) {
if (res.confirm) {
var uid = main.getApplicationInfo().plusGetAttribute("uid");
var Intent = plus.android.importClass('android.content.Intent');
var Build = plus.android.importClass("android.os.Build");
//android 8.0引导
if (Build.VERSION.SDK_INT >= 26) {
var intent = new Intent('android.settings.APP_NOTIFICATION_SETTINGS');
intent.putExtra('android.provider.extra.APP_PACKAGE', pkName);
} else if (Build.VERSION.SDK_INT >= 21) { //android 5.0-7.0
var intent = new Intent('android.settings.APP_NOTIFICATION_SETTINGS');
intent.putExtra("app_package", pkName);
intent.putExtra("app_uid", uid);
} else { //(<21)其他--跳转到该应用管理的详情页
var Settings = plus.android.importClass("android.provider.Settings");
var Uri = plus.android.importClass("android.net.Uri");
var intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
var uri = Uri.fromParts("package", main.getPackageName(), null);
intent.setData(uri);
}
// 跳转到该应用的系统通知设置页
main.startActivity(intent);
} else if (res.cancel) {
}
}
});
}
return
}
if (type === 'ios') {
var UIApplication = plus.ios.import("UIApplication");
var app = UIApplication.sharedApplication();
var enabledTypes = 0;
if (app.currentUserNotificationSettings) {
var settings = app.currentUserNotificationSettings();
enabledTypes = settings.plusGetAttribute("types");
// console.log("enabledTypes1:" + enabledTypes);
if (enabledTypes == 0) {
plus.nativeUI.confirm("消息推送没有开启,是否去开启?", function(e) {
if (e.index == 0) {
var NSURL2 = plus.ios.import("NSURL");
var setting2 = NSURL2.URLWithString("app-settings:");
var application2 = UIApplication.sharedApplication();
application2.openURL(setting2);
plus.ios.deleteObject(setting2);
plus.ios.deleteObject(NSURL2);
plus.ios.deleteObject(application2);
}
}, {
"buttons": ["Yes", "No"],
"verticalAlign": "center"
});
}
plus.ios.deleteObject(settings);
} else {
enabledTypes = app.enabledRemoteNotificationTypes();
if (enabledTypes == 0) {
console.log("推送未开启!");
} else {
console.log("已经开启推送功能!")
}
console.log("enabledTypes2:" + enabledTypes);
}
plus.ios.deleteObject(app);
}
}