美文网首页SwiftiOS
iOS 普通推送和静默推送【公司要求用个推】

iOS 普通推送和静默推送【公司要求用个推】

作者: CoderZb | 来源:发表于2018-06-13 17:47 被阅读824次

    写在前面:应用场景很重要

    如果你的公司有这样一个硬性的需求:用户将APP退出到后台的时候,当该用户收到推送的时候,不让用户感觉到推送过来了,不想打扰用户,但是还想拿到推送内容做一些事情。
    在开发人员看来就是要实现如下功能:通知栏没有文字、没有内容、也没有声音,同时还要能实现客户端退出到后台时,还能执行xcode中的某个特定方法,那么此时就可以用到静默推送


    必须知道个推中这些名词的含义,后面再出现这些名词就不做阐述了

    离线:APP在后台运行/APP未启动/APP被杀死。
    在线:APP在前台运行。
    iOS 个推透传机制

    iOS消息推送方式只有两种:

    APNs的通知栏消息
    个推的透传消息


    以下说的是普通推送和静默推送的不同之处:

    普通推送:当APP离线时,当有推送下达的时候,走的是APNs,所以手机会有铃声、手机顶部出现横幅/通知栏会收到通知。

    • APP离线时,相关方法什么时候执行,看下面1-4就知道了:
      1.只有点开通知栏中的通知进入APP/点开横幅中的通知进入APP,才会执行方法AAA;不点击不执行。
      2.点击应用图标进入APP,一定不会执行方法AAA。
      3.APP离线收到推送,点击应用图标进入APP/点开通知栏中的通知/点开横幅中的通知进入APP,会执行个推提供的 方法BBB的离线的透传消息
      4.APP在线收到推送,就不走APNs,会直接执行个推提供的 方法BBB的在线的透传消息

    • 总结:综合1-4,只要点开APNs发来的通知,那么先执行方法AAA,再执行个推的方法BBB


    方法AAA
    iOS 10之前,点通知,会调用如下方法。
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
         ...   
      做你想做的操作。例如更新UI,跳转界面,文字转语音并读出来,顶部弹框,操作userInfo中的内容。
         ...
    }
    
    
    iOS 10 及以后版本,点击通知,会调用如下方法
    -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler{
        
          ...
         做你想做的操作。例如更新UI,跳转界面,文字转语音并读出来,顶部弹框,操作userInfo中的内容。
          ...
    
        NSLog(@"didReceiveNotification:%@", response.notification.request.content.userInfo);
        // [ GTSdk ]:将收到的APNs信息传给个推统计
        [GeTuiSdk handleRemoteNotification:response.notification.request.content.userInfo];
        completionHandler();
        
    }
    
    方法BBB
    • 离线的透传消息:程序离线收到推送时候,当由离线进入在线的时候会执行(offLine为YES)。离线的时候不会执行该方法。
    • 在线的透传消息:程序在线收到推送的时候会执行(offLine为NO)。
    接收个推推送的透传消息,就会执行如下代理方法
    - (void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId {
    
       拿到payloadData并转成字符串,然后做你想做的操作 :更新UI,跳转界面,文字转语音并读出来,顶部弹框
    
       if (!offLine) {// offLine为NO表示在线的透传消息。
           
        }else{// offLine为YES表示离线的透传消息。
        
       }
    }
    
    
    普通推送->服务端格式:
        $alertmsg=new DictionaryAlertMsg();//  必须有。    声明DictionaryAlertMsg的对象alertmsg
        $alertmsg->body=$msgContent;//  必须有。   为body赋值
        $alertmsg->title=SYS_ZH_NAME;//  必须有。   为title赋值
    
        $apn = new IGtAPNPayload();// 必须有。   声明IGtAPNPayload的对象apn
        $apn->alertMsg=$alertmsg;// 必须有alertmsg,且alertmsg中一定有title以及和body,因为这就是客户端在通知栏/横幅看到的标题和内容。
        $apn->contentAvailable=0;// 必须为0 
        $apn->sound=$client_notice;// 必须有sound
        $apn->badge=1;// 角标,可有可无
        $apn->add_customMsg("msg",$msgContent);// msg,可有可无
    
    普通推送->客户端格式:
    {
      "aps" : {
        "sound" : "notice_type1.caf",// 必须有sound
        "alert" : { // 必须有。    服务器端一定要有alertmsg
          "title" : "一秒招聘",// 必须有
          "body" : "有一条新的招工信息,点击查看详情" // 必须有 
        },
          "badge" : 1,// 角标,可有可无
      },
          "msg" : "有一条新的招工信息,点击查看详情"// msg可有可无
    }
    

    静默推送(安安静静的、用户感知不到):当APP离线时,当有推送下达的时候,通知栏/横幅中没有文字,同时也不会发出声音)

    • 1.应用被杀死或者应用未启动,不会执行如下的代码。
    • 2.应用退出到后台,当收到通知的时候(不点开通知,也不打开APP哦),就会立刻执行如下的代码CCC。 所以静默推送的定义也就出现了:应用收到通知后在后台(background)状态下可以执行下面一段代码CCC,可用于从服务器获取内容更新,做你想做的任何操作(跳转界面,文字转语音并读出声音),所以静默推送不同于其他推送,其他推送不能执行代码CCC。
    • 3.APP离线收到推送,点击应用图标进入APP/点开通知栏中的通知/点开横幅中的通知进入APP,会执行个推提供的 方法DDD的离线的透传消息
    • 4.APP在线收到推送,就不走APNs,会直接执行个推提供的 方法DDD的在线的透传消息
    代码CCC
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
      ...   
    做你想做的操作:这里我用苹果自带的文字转语音播放userInfo里面的指定内容
      ...
    }
    
    方法DDD
    • 离线的透传消息:程序离线收到推送时候,当由离线进入在线的时候会执行(offLine为YES)。离线的时候不会执行该方法。
    • 在线的透传消息:程序在线收到推送的时候会执行(offLine为NO)。
    接收个推推送的透传消息,就会执行如下代理方法
    - (void)GeTuiSdkDidReceivePayloadData:(NSData *)payloadData andTaskId:(NSString *)taskId andMsgId:(NSString *)msgId andOffLine:(BOOL)offLine fromGtAppId:(NSString *)appId {
    
       拿到payloadData并转成字符串,然后做你想做的操作 :更新UI,跳转界面,文字转语音并读出来,顶部弹框
    
       if (!offLine) {// offLine为NO表示在线的透传消息。
           
        }else{// offLine为YES表示离线的透传消息。
        
       }
    }
    
    静默推送->服务端格式:
        $apn = new IGtAPNPayload();
        $apn->alertMsg="";
        $apn->sound="com.gexin.ios.silence";
        $apn->contentAvailable=1;
        $apn->badge=1;
        $apn->add_customMsg("msg",$msgContent);
    
    静默推送->客户端格式:
    {
      "aps" : {
        "content-available" : 1,// 必须为1
        "badge" : 1 // 角标,可有可无
         // 一定不能有alert,因为alert如果有内容,在客户端的通知栏/横幅上会有通知。
      },
      "msg" : "有一条新的招工信息,点击查看详情" // 可有可无
    }
    

    服务端(我们公司是PHP)配置静默推送的格式如下(非常严格,非常严格,非常严格,一项不满足,就不是静默推送,那就变成了普通的有文字有声音的推送):

    1.传入的alertMsg对应的值一定为空或者压根就不传alertMsg字段。

    $apn->alertMsg="";
    
    1. contentAvailable的值一定为1
    $apn->contentAvailable=1;
    

    3.sound对应的值一定为com.gexin.ios.silence.改成其他的字符串的话,应用在后台收到推送时,会听到"铛"的一声。 或者sound对应的值为任意常量也可以实现静音(真机测试过一次,发现确实没有声音。测试次数过少,不是太敢断定,如果有想测试的,可以将sound的值设置成常量试一下)。

    
    $apn->sound="com.gexin.ios.silence";
    

    4.其他的倒无关紧要了,不影响静默推送的格式。


    综合1.2.3.4,静默推送,php服务端要设置的核心代码必定是下面的这种格式:
        $apn->alertMsg="";// alertMsg一定不要有值
        $apn->sound="com.gexin.ios.silence";
        $apn->contentAvailable=1;// 一定为1
    

    以我们项目中静默推送的实战演练

    关键代码如下:
    function IGtTransmissionTemplateDemo($appid,$appkey,$msgContent,$keyType,$keyId,$temp_ietm="",$client_notice="default"){
        $msg = array(
            'keyType' => $keyType,
            'keyId' => $keyId,
            'msg' => $msgContent,
            'nickname' => $temp_ietm
        );
        $msg = json_encode($msg);
        $template =  new IGtTransmissionTemplate();
        $template->set_appId($appid);//应用appid
        $template->set_appkey($appkey);//应用appkey
        $template->set_transmissionType(2);//透传消息类型
        $template->set_transmissionContent($msg);//透传内容
      
        $apn = new IGtAPNPayload();
        $alertmsg=new DictionaryAlertMsg();
        $alertmsg->body=$msgContent;
        $alertmsg->actionLocKey="ActionLockey";
        $alertmsg->locKey=$msgContent;
        $alertmsg->locArgs=array("locargs");
        $alertmsg->launchImage="launchimage";
        //        IOS8.2 支持
        $alertmsg->title=SYS_ZH_NAME;
        $alertmsg->titleLocKey=SYS_ZH_NAME;
        $alertmsg->titleLocArgs=array("TitleLocArg");
        // $apn->alertMsg=$alertmsg;
        $apn->alertMsg="";
        $apn->sound="com.gexin.ios.silence";
        $apn->contentAvailable=1;
        $apn->badge=1;
        $apn->add_customMsg("payload","payload");
        $apn->add_customMsg("keyType",$keyType);
        $apn->add_customMsg("keyId",$keyId);
        $apn->add_customMsg("nickname",$nickname);
        $apn->add_customMsg("msg",$msgContent);
     
        $apn->category="ACTIONABLE";
        $template->set_apnInfo($apn);
    
        return $template;
    }
    
    
    来来来,一起截图圈重点。
    image.png
    以我们公司做的产品为例:雇主在使用iOS客户端发单的时候,后台监听到雇主成功发单后,会访问个推提供的某个SDK,经过一系列的操作。最终iOS客户端在后台收到推送通知的时候,一定会执行xcode中的如下代码
    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{  
        NSLog(@"%@",userInfo);
    }
    

    经过真机调试,符合静默推送(因为我的iOS真机设备在后台收到推送时,没有声音,没有文字,并且还执行了一段xcode中的方法,方法就在下面),

    以下截图是采用静默推送的方式,iOS客户端在后台收到通知时,执行xcode中的下面的方法,打印的userInfo中的内容。

    • (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler;
    // userInfo中的内容
    {
      "_gurl_" : "sdk.open.extension.getui.com:8123",
      "_gmid_" : "OSL-0613_EK270rsK7ZA3frD1xut5B5:6b5a07fe4ef9477caa22c01a93aed697:4f561d975e202fcdb57a47068c5b956b",
      "keyId" : "1134",
      "aps" : {
        "content-available" : 1,
        "mutable-content" : 1,
        "badge" : 1,
        "category" : "ACTIONABLE"
      },
      "keyType" : "7",
      "payload" : "payload",
      "msg" : "有一条新的招工信息,点击查看详情",
      "_ge_" : "1"
    }
    
    
    image.png

    PS:既然已经走到了这里,那么我们就可以实现这种恶搞的效果了:

    用户已经将App退出到后台,此刻来了一个推送,通知栏没有标题和内容,但是用户能听到一段语音。用户很懵逼,不知道是哪个APP发出的声音。
    实现方法:按照上面的一模一样的步骤配置成静默推送。然后配置如下方法,因为下面的这个方法是静默推送必定走的方法(我们在里面偷偷地写上了文字转语音的代码,哈哈哈~~~)

    - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
       // 拿到userInfo中的关键内容,然后用苹果自带的功能进行文字转语音
    }
    
    image.png

    静默推送遇到的坑(静默推送硬生生的做成了普通推送)。

    下面就来看看由于我们公司的后台,设置静默推送不规范导致的iOS客户端在后台收到推送时,有声音有文字的情况。本质上变成了普通推送(有声音有文字)。

    我们公司的后台说是 设置的是静默推送,但实际上从他给我PHP文件来看,没按照静默推送的格式来。导致客户端在后台时,通知栏会有通知的内容展示,同时也会有声音。
    这与静默推送(收到推送,没有声音没有文字)的标准相悖了,导致一直在这个问题上卡了很久。
    在此记录下来,以备不时之需,希望有遇到和我一样问题的朋友,少走一些坑。


    后台设置的有问题的代码
    function IGtTransmissionTemplateDemo($appid,$appkey,$msgContent,$keyType,$keyId,$temp_ietm="",$client_notice="default"){
        $msg = array(
            'keyType' => $keyType,
            'keyId' => $keyId,
            'msg' => $msgContent,
            'nickname' => $temp_ietm
        );
        $msg = json_encode($msg);
        $template =  new IGtTransmissionTemplate();
        $template->set_appId($appid);//应用appid
        $template->set_appkey($appkey);//应用appkey
        $template->set_transmissionType(2);//透传消息类型
        $template->set_transmissionContent($msg);//透传内容
       
    
        $apn = new IGtAPNPayload();
        $alertmsg=new DictionaryAlertMsg();
        $alertmsg->body=$msgContent;
        $alertmsg->actionLocKey="ActionLockey";
        $alertmsg->locKey=$msgContent;
        $alertmsg->locArgs=array("locargs");
        $alertmsg->launchImage="launchimage";
        //        IOS8.2 支持
        $alertmsg->title=SYS_ZH_NAME;
        $alertmsg->titleLocKey=SYS_ZH_NAME;
        $alertmsg->titleLocArgs=array("TitleLocArg");
    
        $apn->alertMsg=$alertmsg;
        $apn->contentAvailable=1;
        $apn->sound=$client_notice;
        $apn->badge=1;
        $apn->add_customMsg("payload","payload");
        $apn->add_customMsg("keyType",$keyType);
        $apn->add_customMsg("keyId",$keyId);
        $apn->add_customMsg("nickname",$nickname);
        $apn->add_customMsg("msg",$msgContent);
        $apn->category="ACTIONABLE";
        $template->set_apnInfo($apn);
    
        return $template;
    }
    
    
    截图展示后台设置的有问题的关键代码
    image.png
    分析静默推送格式不规范会出现哪些问题

    以下情况满足的前提条件:②的值为1,即静默推送

    • ①是变量,当①有值时,iOS客户端在后台收到推送时,通知栏会有推送标题和内容的展示。

    • ①是变量,当①没有值时,iOS客户端在后台收到推送时,通知栏没有推送标题和内容的展示。

    • ③是变量,当③有值时:

      • 如果xcode中放置的音频文件和sound对应的值一样,那么iOS客户端在后台收到推送时,就会自动
        读出音频文件的声音。
        - 的是的撒的
      • 如果xcode中放置的音频文件和sound对应的值不一样,或者xcode中根本没有音频文件,那么iOS客户端在后台收到推送时,就会听见铛的一声。
    • ③是变量,当③没有值时,那么iOS客户端在后台收到推送时,就会听见铛的一声。

    PS:以下①和③不是变量的情况。当然仍满足②是静默推送
    PHP后台代码中,将①设置成空字符串,iOS客户端在后台收到推送时,通知栏没有推送标题和内容的展示
    PHP后台代码中,将③设置成非com.gexin.ios.silence的任意字符串或者不和xcode中的音频文件重名的,这时iOS客户端在后台收到推送的时候,就会听见铛的一声。


    打印的内容如下: 经过测试iOS客户端在后台收到推送时,会读取xcode中存放的音频文件notice_type1.caf,同时通知栏会展示标题(一秒招聘) 和 内容(有一条新的招工信息,点击查看详情)
    {
      "_gurl_" : "sdk.open.extension.getui.com:8123",
      "_gmid_" : "OSL-0613_WzPFJBFf1BAXhORnt7bRn2:e34f8f8517034efa9773415a8d33190f:ada94b80070b9be823f25f8ea4577b92",
      "keyId" : "1131",
      "aps" : {
        "sound" : "notice_type1.caf",
        "content-available" : 1,
        "alert" : {
          "loc-args" : [
            "locargs"
          ],
          "title" : "一秒招聘",
          "title-loc-args" : [
            "TitleLocArg"
          ],
          "title-loc-key" : "一秒招聘",
          "action-loc-key" : "ActionLockey",
          "body" : "有一条新的招工信息,点击查看详情",
          "loc-key" : "有一条新的招工信息,点击查看详情",
          "launch-image" : "launchimage"
        },
        "mutable-content" : 1,
        "category" : "ACTIONABLE",
        "badge" : 1
      },
      "keyType" : "7",
      "payload" : "payload",
      "msg" : "有一条新的招工信息,点击查看详情",
      "_ge_" : "1"
    }
    
    以上xcode控制台输出的json数据若要符合静默推送,那么必须做如下修改:对应的让服务端改掉对应的内容即可
    image.png
    注意:本地存放的音频文件一定要放在该工作目录下
    image.png

    PS:当然,如果返回的json数据里面sound的值为"1"或者任意字符串就会出现铛的一声,如果sound的值能和xcode的该路径下的音频文件匹配上,那么iOS客户端在后台收到推送时,会自动读出匹配到的音频。


    写到这里我在想,如果公司没有强制说要用户在后台的时候,不许在通知栏中展示内容和标题以及发出声音,那么你可以设置成在展示内容和标题以及会发出声音。此时content-available设置为0和1就没有区别了,因为你只要保证如下条件满足即可:

    
       // alert里面有内容 ; 必须保证有值
       $apn->alertMsg=$alertmsg;
        // 静默推送 1
        $apn->contentAvailable=1;
        // sound对应的值是字符串com.gexin.ios.silence或者sound对应的值是常量会静音。 
        // sound对应的值是常量,比如$apn->sound=1;会听见铛的一声。
        // sound对应的值是变量,如果xcode中的音频文件名能和变量对应起来,推送来的时候,会自动检索xcode中的音频文件,检索到就会读出来
        $apn->sound=$client_notice;
    

    我们项目中有这么个需求,APP中所有的音频要么采用文字转语音,要么用录制好的音频文件,但是因为推送的内容有变量,比如xxx签到了您的家政服务工作,所以不能用录制好的音频文件。所以需求就这么出现了:
    当推送过来的时候(在线、离线),有通知、系统推送来的铛的一声没做要求、 文字转语音。明确规定,要对推送过来的通知内容进行文字转语音,不能用录制好的音频文件

    分析(在线走个推,所以肯定能文字转语音,这里就不说了,以下分析的是离线(APP在后台运行/APP未启动/APP被杀死)的情况),不考虑点击通知进入APP的情况:
    • 如果单纯采用标准的静默推送,肯定达不到效果:因为只要符合静默推送的格式,来推送的时候,没有通知也没有声音(铛的一声)。

      • 当程序在后台的时候,推送来的时候,还能执行一段方法(可以文字转语音读出来)。效果:通知栏没有通知、铛的一声有无(看后台配置的sound对应的值)、文字转语音。所以不符合
      • APP被杀死或者APP未启动的时候,推送来的时候,不会执行这段方法(代码都不走了,肯定没法进行文字转语音了)。效果:通知栏没有通知、铛的一声有无(看后台配置的sound对应的值)、没有文字转语音。所以不符合
    • 如果单纯采用标准的普通推送,肯定达不到效果

      • 当程序离线(APP在后台运行/APP未启动/APP被杀死)的时候,推送来的时候,有通知,有声音(铛的一声,不是文字转语音的声音),由于不能用录制好的音频文件,所以我将xcode里面的音频文件删除了,因此不会读音频文件。普通推送不点击通知,离线不会走xcode项目里面的任何代码,所以没法进行文字转语音。效果:通知栏有通知、铛的一声有无(看后台配置的sound对应的值)、没有文字转语音。所以不符合
    • 采用普通推送+静默推送混合的方式,APP在后台运行能符合要求,APP未启动/APP被杀死不符合要求:
      先说一下普通推送+静默推送混合的后台大致格式,具体参考上面的代码:

        // alert里面有内容 。普通推送alert中有内容
        $apn->alertMsg=$alertmsg;
        // 静默推送 1  之所以设置为1,是为了走xcode里面的某个方法
        $apn->contentAvailable=1;
        // sound对应的值是字符串com.gexin.ios.silence或者sound对应的值是常量会静音。 
        // sound对应的值是常量,比如$apn->sound=1;会听见铛的一声。
        // sound对应的值是变量,如果xcode中的音频文件名能和变量对应起来,推送来的时候,会自动检索xcode中的音频文件,检索到就会读出来
        $apn->sound=1;// 有铛的声音
    
    • 当程序在后台的时候,推送来的时候,有通知,铛的一声有无(看后台配置的sound对应的值),同时还能执行xcode里面的一段方法(该段方法里面写了文字转语音的代码)。效果:通知栏有通知、铛的一声有无(看后台配置的sound对应的值)、文字转语音。所以符合
    • APP被杀死或者APP未启动的时候,推送来的时候,通知栏有通知、铛的一声有无(看后台配置的sound对应的值)、没有文字转语音。所以不符合
    所以,针对我们公司的要求,只能采用普通推送+静默推送混合的方式,这种方式APP在后台的时候满足公司的需求,APP被杀死或者APP未启动的时候,不满足需求,这是苹果的机制问题,这是最能契合公司需求的做法了,目前只能这么做,如果有其他方法,朋友们麻烦@一下我哦。

    ................................

    相关文章

      网友评论

        本文标题:iOS 普通推送和静默推送【公司要求用个推】

        本文链接:https://www.haomeiwen.com/subject/rzodeftx.html