公司要求我使用Vue写的App具有消息推送功能。而我知道Vue打包成App,则使用Hbuilder的SDK配置,发现他只有小米推送和个推。由于个推在市场上使用量比较多,于是就开启了我的Vue消息推送个推之旅。

  1. 而此时发现个推的开发者中心注册账号时,需要:

这些他必须要得提供。我们知道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";
        
        /**
         * 推送透传消息给某个人
         * @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. 多人使用一台手机(用户1手机忘记携带,使用用户2)

  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中添加消息的监听最为合适,于是就有了这样的代码:

至此消息推送完成

Logo

前往低代码交流专区

更多推荐