1***@qq.com
1***@qq.com
  • 发布:2019-03-18 22:17
  • 更新:2020-11-30 13:59
  • 阅读:7137

个推平台消息推送踩坑经验分享

分类:HTML5+

以下为官方说明
使用个推平台推送消息,在ios平台和安卓平台的运行机制并不完全相同,
下面对安卓平台和IOS平台进行分别描述
个推支持安卓可以发送普通消息和透传消息方式,ios只支持透传消息这种方式推送。

(一)IOS平台
IOS平台在处理消息时会因为程序是否在线处理逻辑会有不同

1.应用在线:
应用在线时服务器推送的消息不会进入消息中心。
如果页面中监听了“receive”事件则会触发事件的回调。
如果消息是通过APS通道发送到终端,用户可以在“receive”事件回调的“PushMesage”对象
中获取“aps”属性的值。

2应用不在线:
如果当前应用不在线,服务器推送的消息会进入系统消息中心。当用户点击消息,
则会启动HTML5+应用,并且在监听了“click”事件的页面中触发事件的回调。

3.本地消息:
当开发者创建本地消息时,本地消息会进入消息中心。如果开发者监听了“receive”事件,
则会在监听页面触发receive事件回调。如需要区分收到的消息是否是本地消息,
用户需要在payload节点添加标识。

(二)Android平台:
对安卓平台发送的普通push消息和符合格式的透传消息都会进入系统的消息中心。
透传消息如不符合格式则会触发监听页面的“receive”事件不会显示在消息中心。
安卓平台发送的普通消息都会进入消息中心,用户可以点击触发消息。

1.发送普通消息:
服务器可以向安卓平台发送三种类型的普通消息“通知”“下载”“网址”,
发送“通知”消息会启动HTML5+应用,如果是“下载”消息则会调用系统的下载管理器
下载指定文件。点击“网址”消息则会调用系统浏览器打开指定的网址。

2.发送透传消息:
当设备收到服务器发送的透传消息时,不会触发页面监听的receive事件。
当用户点击消息中心消息时会触发监听页面的“click”事件。
如果用户点击多个消息时,会多次触发“click”事件。
不符指定合格式的透传消息不会进入系统的消息中心,
会在监听“receive”事件的页面触发事件回调。

  • 踩坑总结如下:
  • 1.实际测试发现大部分安卓机只会在应用在后台或者在线时才会收到消息,点击消息会只会触发newintent的事件,而click和receive事件不会触发(暂无发现什么情况下会触发);
  • 2.而苹果机离线或者后台应用时收到消息时,点击通知栏消息只触发newintent事件,当应用在前台时,只触发receive事件;(ios暂无发现什么情况会触发click事件)
  • 3.经测试发现eval("(" + str + ")")转json这个方法在ios并不会执行,安卓机正常执行;
  • 4.由于要兼容安卓的透传消息的格式,所以导致payload不是标准,所以ios接收的payload并不是标准的json字符串,要做特殊处理
  • 5.parseJSON(str)的str只接收标准的json字符串,不然会报错。
  • 6.如果obj本来就是一个JSON对象,那么使用eval()函数转换后(哪怕是多次转换)还是JSON对象,但是使用parseJSON()函数处理后会有问题(抛出语法异常)。参考:https://www.cnblogs.com/guoziyi/p/6003752.html
    */

一、以下是watcher.js实现逻辑

if(window.plus) {  
    newsClick();  
} else {  
    document.addEventListener('plusready', newsClick, false);     
}  

function newsClick() {  
    //获取个推 CID  
    //mui.toast(plus.push.getClientInfo().clientid);  
    // 监听plusready事件    
    //仅支持竖屏显示  
    plus.screen.lockOrientation("portrait-primary");  
    plus.push.addEventListener("click", function(msg) {//为了兼容处理,暂时未发现可触发的情况  
        msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');  
        if(plus.os.name=='iOS') {//ios当前应用离线时  
            if(msg.aps){  
                pushGetRun(msg.payload);  
            }  
        }else{//安卓用户点击消息中心的消息会触发监听页面的“click”事件  
            if(msg.payload){  
                var payload = eval('(' + msg.payload + ')');  
                pushGetRun(payload);  
            }  
        }  
    }, false);  
    plus.push.addEventListener("receive", function(msg) {  
        //获取透传数据,统一将回调对象msg处理成json对象  
        msg = (plus.os.name == 'iOS') ? msg : eval('(' + msg + ')');  
        if(plus.os.name == 'iOS'){//IOS应用在线时会触发“receive”事件的回调  
            if(msg.payload){  
                if(typeof(msg.payload) == "string"){  
//                  mui.alert("payload(String): " + msg.payload);  
                    //字符串处理  
                    var payloadJson = toJSON(toJSONStr2(toJSONStr1(msg.payload))); //这个是透传消息的内容,格式为`{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`  
                    if(payloadJson.payload){  
                        newsConfirm(payloadJson.payload);//弹出新消息层  
                    }  
                }else if(typeof(msg.payload) == "object"){  
                    if(msg.payload.payload){  
                        var payloadObj = null;  
                        if(typeof(msg.payload.payload) == 'string'){  
                            payloadObj = toJSON(toJSONStr2(toJSONStr1(msg.payload.payload)));//转为object  
                        }else if(typeof(msg.payload.payload) == "object"){  
                            payloadObj = msg.payload.payload;  
                        }  
                        if(payloadObj){  
                            newsConfirm(payloadObj);//弹出新消息层  
                        }else{//异常处理  
//                          clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页  
                        }  
                    }  
                }     
            }  
        }else {//安卓不符指定合格式的透传消息不会进入系统的消息中心,会在监听“receive”事件的页面触发事件回调  
            if(msg.payload){  
                newsConfirm(msg.payload);//弹出新消息层  
            }else{//异常处理  
            }     
            //创建本地消息  
//          plus.push.createMessage(msg.content, msg.payload, {  
//              title: msg.title,  
//              cover: false  
//          });  
       }  
    }, false);  

    function pushGetRun(payload) {//用参数打开指定页面  
        //eval()函数将字符串转换时需要区分是否是ios  
        var data = (plus.os.name == 'iOS') ? payload : eval('(' + payload + ')');  
        if(data.url&&data.hasOwnProperty("params")){  
            clicked(data.url, data.params);  
        }else{//异常处理  
            mui.toast("参数缺失或错误");  
            clicked("_www/view/index.html", {"subpage_id":"_www/view/home/home.html"});//默认打开首页  
        }  
    }  

    //程序从后台被第三方程序调用并传入新意图事件,通过测试发现,安卓只调用该事件,ios应用离线或者后台时只会调用此事件,ios应用处于前台会调用receive的监听事件  
    document.addEventListener("newintent", openWebviewFromOthers, false);  
    //获取通知栏(app未启动)点击、第三方程序启动本app  
    function openWebviewFromOthers() {  
        var args = plus.runtime.arguments;  
        if(args.indexOf('wechat') < 0 && args) {  
//          mui.toast("----args----" +JSON.stringify(args));  
            pushGetRun(args);  
        }  
    }  

    function newsConfirm(payload){  
        plus.nativeUI.confirm("收到一条新消息,是否立即查看", function(e) {  
            if(e.index == 0) {  
                pushGetRun(payload);  
            }  
        }, "新消息通知", ["查看", "忽略"]);  
    }  
};  

/*  
 * 针对ios不能执行eval("(" + str ")")来强制转化成json对象,  
 * 所以要自定义函数来将不标准的字符串转化成标准的字符串,在利用JSON.parse()方法来转化成json对象;  
 * 以下为调用例子:  
 * var a = `{title:"通知标题",content:"通知内容",payload:'{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'}`;  
 * toJSON(toJSONStr2(toJSONStr1(a)));//测试  
 */  

function toJSONStr1(str){  
//全局将字符串  '{ 和  }' 替换成   {  和   }   ,主要是为了统一"个推推送消息的透传内容的格式(而安卓需要传字符串而导致不是payload不是json对象)  
  return str.replace(/'{/g,"{").replace(/}'/g, "}");  
}  
function toJSONStr2(str) { //全局将属性名添加上双引号  ""  
  return str.replace(/([\$\w]+)\s*:/g, function(_, $1){return '"'+$1+'":'});  
}  
function toJSON(str) { //处理标准格式的字符串成json对象  
  return JSON.parse(str);  
}

二、在view目录新建一个watcher.html,引入watcher.js即可;
三、在app入口文件 index.html做以下声明,用于应用启动时全局监听:


                //消息事件监听  
                var watcherObj = plus.webview.getWebviewById("_www/view/watcher.html");  
                if(!watcherObj){//不存在才创建  
                    var watcher = plus.webview.create("_www/view/watcher.html", "_www/view/watcher.html");  
                    //创建完隐藏  
                    watcher.hide();  
                }

四、个推平台上的使用:
由于个推对于推送通知(普通消息)的功能目前仅支持安卓用户,所以为了统一和兼容,所以要使用“透传消息”来进行推送;
”透传内容“------”消息内容“的参考例子:

{  
    title: "通知标题",  
    content: "通知内容",  
    payload: '{"url":"_www/view/discovery/discoverydetail.html","params":{"article_id":51}}'  
}

IOS参数设置----payload的自定义值参考如下:

{  
    "url": "_www/view/discovery/discoverydetail.html",  
    "params": {  
        "article_id": 51  
    }  
}

五、特别注意:经过测试,魅族机器 Notification 的奇葩问题,就是其的消息内容(对应上面”透传内容“--”消息内容“的content的值)不能带有中文字符的!和英文字符的!(参考:http://blog.csdn.net/u013045971/article/details/70173532);但是消息标题可以带;如果非要使用感叹号的话,可以使用特殊字符的感叹号﹗(来源:http://xh.5156edu.com/page/18466.html)

六、以下附件是个推平台上要注意的事项截图;

以上全部,欢迎大家一起讨论!

2 关注 分享
6***@163.com aliang888

要回复文章请先登录注册

5***@qq.com

5***@qq.com

ios只支持透传消息这种方式推送。这句话不准确吧,应该是uniPush后台管理界面中不支持推送通知这种类型
2020-11-30 13:59
x***@sina.com

x***@sina.com

回复 1***@qq.com :
我已经解决了,参考:https://ask.dcloud.net.cn/article/36622
2019-11-30 21:34
x***@sina.com

x***@sina.com

回复 willKing :
我已经解决了,参考:https://ask.dcloud.net.cn/article/36622
2019-11-30 21:34
willKing

willKing

回复 1***@qq.com :
您解决了离线推送了吗
2019-05-22 22:25
willKing

willKing

我也是离线推送一直不成功
2019-05-22 22:24
1***@qq.com

1***@qq.com

楼主坑1“大部分安卓机只会在应用在后台或者在线时才会收到消息”这个咋解决的
2019-04-28 13:34