公司要求我使用Vue写的App具有消息推送功能。而我知道Vue打包成App,则使用Hbuilder的SDK配置,发现他只有小米推送和个推。由于个推在市场上使用量比较多,于是就开启了我的Vue消息推送个推之旅。
- 而此时发现个推的开发者中心注册账号时,需要:
这些他必须要得提供。我们知道android包名和IOS bundleID就是我们使用Hbuilder的包名,当时他没有android签名,这个时候没办法就得知道Hbuilder的签名,于是找到了这两篇文章:
http://ask.dcloud.net.cn/article/68
https://segmentfault.com/a/1190000011376912
通过这两篇文章,我生成了android签名。(android的签名是固定值)
- 接下来我们需要了解推送的原理。在个推的开发者平台,有这样一个图:在这个图中我们知道个推推送没那么简单,也就代表了我们需要书写服务端和在客户端集成他们的SDK。基本流程:
1.第三方应用集成个推SDK,个推SDK运行后获取CID返回给第三方应用,由第三方应用保存至其应用服务器;
2.第三方应用服务器调用推送API进行消息推送,个推SDK将接收到的推送消息回调给App进行处理
-
所以此时我们需要在后台书写服务端。查看文档我们发现只能使用透传消息模式,于是服务端是这样的:
public class Getui { //定义常量, appId、appKey、masterSecret 采用本文档 "第二步 获取访问凭证 "中获得的应用配置 private static String appId = "*******"; private static String appKey = "******"; private static String masterSecret = "*****"; private static String url = "http://sdk.open.api.igexin.com/apiex.htm"; //线下测试地址 /*private static String appId = "1jNosQz0ZJ6GwTOFQ4qid6"; private static String appKey = "ZuAR8ZsaEV5Q3RM3bAzR69"; private static String masterSecret = "GLaO0ooRIw7RCR5rcumgl8"; private static String url = "http://sdk.open.api.igexin.com/apiex.htm"; private static String clientId="c54318cc13e4e8e9548ef60703e75629"; private static String app_title="常祁高速"*/; /** * 推送透传消息给某个人 * @param clientId * @param text * @param transmissionContent */ public static boolean pushSingleUser(String clientId, String text, String transmissionContent, String id, String type){ IGtPush push = new IGtPush(url, appKey, masterSecret); // 通知透传模板 TransmissionTemplate template = notificationTemplate(text, transmissionContent, id, type); SingleMessage message = new SingleMessage(); message.setData(template); // 设置消息离线,并设置离线时间 message.setOffline(true); // 离线有效时间,单位为毫秒,可选 message.setOfflineExpireTime(24 * 1000 * 3600); Target target = new Target(); //Target target2 = new Target(); target.setAppId(appId); target.setClientId(clientId); IPushResult ret =null; try{ ret=push.pushMessageToSingle(message, target); } catch (RequestException e) { ret=push.pushMessageToSingle(message, target, e.getRequestId()); return false; }catch (Exception e) { return false; } if (ret != null) { System.out.println(ret.getResponse().toString()); return true; } else { System.out.println("服务器响应异常"); return false; } } public static boolean pushListUser(List<String> listStr, String text, String transmissionContent, String id, String type){ IGtPush push = new IGtPush(url, appKey, masterSecret); // 通知透传模板 TransmissionTemplate template = notificationTemplate(text, transmissionContent, id, type); ListMessage message = new ListMessage(); message.setData(template); // 设置消息离线,并设置离线时间 message.setOffline(true); // 离线有效时间,单位为毫秒,可选 message.setOfflineExpireTime(24 * 1000 * 3600); // 配置推送目标 List<Target> targets = new ArrayList<Target>(); for(String str:listStr){ Target target=new Target(); target.setAppId(appId); target.setClientId(str); targets.add(target); } // taskId用于在推送时去查找对应的message String taskId = push.getContentId(message); IPushResult ret =push.pushMessageToList(taskId, targets); if(ret!=null){ return true; }else{ return false; } } /** * 透传消息 * @param text * @param transmissionContent * @return */ public static TransmissionTemplate notificationTemplate(String text,String transmissionContent, String id, String type) { TransmissionTemplate template = new TransmissionTemplate(); template.setAppId(appId); template.setAppkey(appKey); template.setTransmissionContent(transmissionContent); template.setTransmissionType(2); APNPayload payload = new APNPayload(); //在已有数字基础上加1显示,设置为-1时,在已有数字上减1显示,设置为数字时,显示指定数字 payload.setAutoBadge("+1"); payload.setContentAvailable(1); //ios 12.0 以上可以使用 Dictionary 类型的 sound payload.setSound("default"); payload.setCategory("$由客户端定义"); //app跳转到指定页面的时候用 Map<String,String> map = new HashMap<String,String>(); map.put("id", id); map.put("type", type); payload.addCustomMsg("payload", map); payload.setVoicePlayType(2); payload.setVoicePlayMessage(transmissionContent); //简单模式APNPayload.SimpleMsg payload.setAlertMsg(new APNPayload.SimpleAlertMsg(text)); template.setAPNInfo(payload); return template; } }
接下来是客户端的消息接收。通过上面个推的图片我们知道,每个手机必须得注册,告诉服务器这台手机需要进行消息推送,那么这个注册的过程,就是我们每次登录app的用户。
-
那么关于注册手机的问题:
-
多人使用一台手机(用户1手机忘记携带,使用用户2)
-
一人使用多台手机(测试情况,用户1使用手机切换账号)
上诉两种情况,我们只针对性处理:只记录当前用户最后一位登录用户的活跃状态,于是在终端就有了这样的代码:
var clientInfo=plus.push.getClientInfo();
var pushInfo={};
pushInfo.clientid=clientInfo.clientid;
var imei=plus.device.imei;
if(imei==="" || imei===null || imei===undefined){
imei='';
}else if(imei.length>1){
imei=imei.split(",")[0];
}
pushInfo.imei=imei;
var imsi=plus.device.imsi;
if(imei===null || imei.length===0){
imsi='';
}else{
imsi=imsi[0];
}
pushInfo.imsi=imsi;
pushInfo.model=plus.device.model;
pushInfo.vendor=plus.device.vendor;
var uuid=plus.device.uuid;
if(uuid==="" || uuid===null || uuid===undefined){
uuid='';
}else if(uuid.length>1){
uuid=uuid.split(",")[0];
}
var u = navigator.userAgent, app = navigator.appVersion;
var isAndroid = u.indexOf('Android') > -1 || u.indexOf('Linux') > -1; //android终端或者uc浏览器
var isiOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/); //ios终端
if(isAndroid){
pushInfo.phoneType='Android';
}else if(isiOS){
pushInfo.phoneType='IOS';
}else{
pushInfo.phoneType='';
}
pushInfo.uuid=uuid;
back(pushInfo)
值得注意的是:这个方式有时候无法保证其有效性和及时性。我们必须加上setTimeout
- 终端消息接收处理
当消息来到时,我们发现透传模式下,我们只能使用本地消息进行创建,无法让app的SDK实现消息推送。如此这样,我们需要借助HTML5 PLUS的创建消息,然后在点击消息通知后,进行跳转。
document.addEventListener( "plusready", function(){
plus.runtime.setBadgeNumber(0);
plus.push.setAutoNotification(true);
// 监听点击消息事件
plus.push.addEventListener( "click", function( msg ) {
/*
根据需要填写
*/
//解析消息通知,进行跳转
messageHerf(msg)
}, false );
// 监听在线消息事件
plus.push.addEventListener( "receive", function( msg ) {
//创建消息通知
messagePush('create', msg.content, msg.payload, msg.payload.type, function () {
});
}, false );
}, false );
//第三方启动app
document.addEventListener("newintent", function() {
openWebviewFromOthers();
});
问题又来了。我们在那里监听合适呢?这个问题让我仔细探究了Vue的生命周期,发现main.js中添加消息的监听最为合适,于是就有了这样的代码:
至此消息推送完成