之前项目需要,接入个推,实现 serverAPP 进行消息推送,为了简化操作,我使用了restAPI,同时将代码整合进了一个model,直接 use model; 即可。

之前的model还是有一些瑕疵,因此做了改动,同时功能上增加了一个新的推送接口:

toList 群推

QQ截图20170526160509.jpg

读这篇文章之前,建议看看上一篇文章中一些文字部分(代码部分可以忽略,因为已经更新了)。

原文地址:

一、变化

主要的变化时参数方面的变化,参数变化主要体现在通知消息,而透传消息没有做任何的改动。

1. 通知消息的参数变化

  • public function sendToClient($clientID,$content,$transmission_content='')
  • public function sendToAllNotification($content,$transmission_content='')
  • public function sendToListNotification($cidList=[],$content,$transmission_content='')

新的通知消息参数中,去掉了title和text两个参数,改为用content来实现,这样子能够极大的增强可配置性

个推的推送中消息的内容和形式是可以确定的,可以查看文档:

因此style中现在的写法就变成了如下所示

'style'=>[
    'type'=>1,
    'text'=>$content['text'],
    'title'=>$content['title'],
    'logourl'=>$content['logourl'],
    'is_ring'=>$content['is_ring'],
    'is_vibrate'=>$content['is_vibrate'],
    'is_clearable'=>$content['is_clearable'],
    ],

需要注意的是,之前的model中我使用的 type 是 0 ,但是新的model中我是用的 type 都是 1

两者的主要的区别在于:

  • type=0使用的是安卓原生通知,没有logourl这个参数,有logo参数,但是logo的图片地址必须是客户端SDK嵌入进去的。
  • type=1使用的个推的默认通知样式,有logourl参数,没有logo参数,logourl可以是一个互联网图片,指定一个url图片的地址来显示,相比于type=0,type=1的图片样式能更大程度的有自己决定

2. 增加了 sendToListNotification 方法,用于向cliendidList推送消息

参数上,sendToListNotification 方法的$cidList是一个数组。

使用tolist推送,比较重要的一点在于:

  • 需要调用两次接口,一次用来保存消息体,一次用来推送消息
  • 推送消息的API需要使用保存消息体的API返回的taskid

3. 每次调用接口均进行本地缓存

可以看到Model中每次调用都会有一个 $this->cache_getui_res($res);

主要是为了能够缓存一下每次的调用结果,能够用于分析。

默认我是在thinkphp5中使用的,因此如果用不同的开发框架的话,可以修改一下这个方法,来适应具体的框架。QQ截图20170526181144.jpg

二、使用方式

以新加入的 tolist 群推举例:

下面是我在别的class中写的统一发送通知的方法:

  • type用于标识调用单推还是群推

    • 因为我的业务中,type还有别的标识作用,这里就不写出来了。
  • $configInfo 是我在配置文件中配置的通用信息
    1.jpg
  • $content 是发送通知信息的参数
    /**
     *  发送推送通知的消息
     *  - cid可能是一个,也可能是多个
     * @param $type int
     * @param $cid
     * @param $transmission_str string
     *
     */
    protected function sendToClientByGetui($type=0,$cid){
        try{
            $Getui=new Getui();
            // 获取配置内容
            $configInfo=Config::get('apiserver.notification_cid');
            // 拼接基本的content数组
            $content=[
                'title'=>$configInfo['title'],
                'text'=>$configInfo['text'],
                'logourl'=>$configInfo['logourl'],
                'is_ring'=>true,
                'is_vibrate'=>true,
                'is_clearable'=>true,
            ];
            // type=0 说明只发送一个
            if($type==0){
                $res=$Getui->sendToClient($cid,$content,'');
            }else{
                // 多个cid都需要发送
                $res=$Getui->sendToListNotification($cid,$content,'');
            }
            return $res;
        }catch (\Exception $exception){
            $res=['res'=>$exception->getMessage(),'time'=>time()];
            return $res;
        }
    }

三、Getui.php Model代码

<?php
/**
 * Author: Postbird
 * Date  : 2017/4/29
 * time  : 11:11
 * Site  : www.ptbird.cn
 * There I am , in the world more exciting!
 */
namespace app\index\model;

use think\Cache;
use think\Config;
use think\Model;

class Getui extends Model{

    /**
     * 获取authtoken,从缓存中获取
     * 有效时间是1天,如果超时则重新获取
     * 为了保险起见,保存时间为23小时,超时刷新
     */
    public function getAuthToken(){
        // 从缓存中获取 [缓存中保存的字段标识是:getui_auth_token]
        $authToken=Cache::get('getui_auth_token');
        // 如果存在token参数,则说明没有过期
        if($authToken){
            // 返回auth_token
            return $authToken;
        }else{
            // 刷新token,会返回数组格式
            $res=$this->refreshAuthToken();
            // 返回的数组中 result=ok 代表获取成功
            if($res['result']=='ok'){
                // 向缓存中存储 token,有效时间是23小时
                Cache::set('getui_auth_token',$res['auth_token'],82800);
                // 将结果存储到redis中
                $this-cache_getui_res($res);
                return $res['auth_token'];
            }// 将结果存储到redis中
            $this->cache_getui_res($res);
            return false;
        }
    }
    /**
     * 刷新或者初次获取 authtoken
     * 通过 restAPI刷新
     * protected 方法
     */
    protected function refreshAuthToken(){
        // 从配置中获取相关的数据
        $appKey=Config::get('getui.appkey');
        $appId=Config::get('getui.appid');
        $masterSecret=Config::get('getui.mastersecret');
        // 获取毫秒数 秒数*1000
        $timestamp=time()*1000;
        // 构建sign
        $sign=strtolower(hash('sha256',$appKey.$timestamp.$masterSecret,false));
        // 构建需要发送的数据
        $dataArr=[
            'sign'=>$sign,
            'timestamp'=>$timestamp,
            'appkey'=>$appKey,
        ];
        // 个推所有的api发送的数据都是json格式,因此不能发送函数,需要发送json
        $content=json_encode($dataArr);
        // 构建header
        $header=array(
            'Content-Type: application/json',
        );
        $url='https://restapi.getui.com/v1/'.$appId.'/auth_sign';
        // 发送http post请求
        $res=curl_post_json($url,$header,$content);
        $res=json_decode($res,true);
        // 返回数组格式,如果res.result是ok,说明没问题
        // 将结果存储到redis中
        $this->cache_getui_res($res);
        return $res;
    }
    /**
     * 关闭鉴权
     */
    public function closeAuthToken(){
        $appId=Config::get('getui.appid');
        // 获取auth_token,调用函数获取,如果超时则会自动刷新
        $authToken=$this->getAuthToken();
        if(!$authToken){
            return false;
        }
        // 构建header
        $header=[
            'Content-Type: application/json',
            'authtoken:'.$authToken
        ];
        $url='https://restapi.getui.com/v1/'.$appId.'/auth_close';
        $res=curl_post_json($url,$header);
        $res=json_decode($res,true);
        // 返回数组格式,如果res.result是ok,说明没问题
        // 将结果存储到redis中
        $this->cache_getui_res($res);
        return $res;
    }
    /**
     *  向某个用户推送消息
     *  cid = fd98882bef6f1bade6bffc85574436db
     *  cid = 260cc489c1b6bb13b7cb933f89020ad0
     *  - $content 是一个报刊在notification->style下的数组内容
     *    其中包括了  title,text,logo,logourl,is_ring,is_vibrate,is_clearable
     * @param $clientID string
     * @param $content array
     * @param $transmission_content string
     */
    public function sendToClient($clientID,$content,$transmission_content=''){
        $appKey=Config::get('getui.appkey');
        $authToken=$this->getAuthToken();
        $appId=Config::get('getui.appid');
        $content=array(
            'message'=>[
                "appkey"=>$appKey,
                "is_offline"=>false,
                "msgtype"=>"notification"
            ],
            'notification'=>[
                'style'=>[
                    'type'=>1,
                    'title'=>$content['title'],
                    'text'=>$content['text'],
                    'logourl'=>$content['logourl'],
                    'is_ring'=>$content['is_ring'],
                    'is_vibrate'=>$content['is_vibrate'],
                    'is_clearable'=>$content['is_clearable'],
                ],
                "transmission_type"=> true,
                "transmission_content"=> $transmission_content
            ],
            "cid"=>$clientID,
            "requestid"=> "".time()
        );
        $content=json_encode($content);
        $header=array(
            'Content-Type: application/json',
            'authtoken:'.$authToken
        );
        $url='https://restapi.getui.com/v1/'.$appId.'/push_single';
        //
        $res=curl_post_json($url,$header,$content);
        $res=json_decode($res,true);
        // 将结果存储到redis中
        $this->cache_getui_res($res);
        return $res;
    }
    /**
     * 群发消息
     * - 向所有的app发送透传消息
     * @param $message
     * @return array
     */
    public function sendToAllTransmission($message){
        $appKey=Config::get('getui.appkey');
        $authToken=$this->getAuthToken();
        $appId=Config::get('getui.appid');
        $content=[
            'message'=>[
                "appkey"=>$appKey,
                "is_offline"=>false,
                "msgtype"=>"transmission"
            ],
            'transmission'=>[
                "transmission_type"=>false,
                "transmission_content"=>$message,
            ],
            'requestid'=>"".time(),
        ];
        $content=json_encode($content);
        $header=[
            'Content-Type: application/json',
            'authtoken:'.$authToken
        ];
        $url='https://restapi.getui.com/v1/'.$appId.'/push_app';
        //
        $res=curl_post_json($url,$header,$content);
        $res=json_decode($res,true);
        return $res;
    }
    /**
     * 群发消息
     * - 向所有的app发送notification消息
     * @param $content
     * @param $transmission_content string
     * @return array
     */
    public function sendToAllNotification($content,$transmission_content=''){
        $appKey=Config::get('getui.appkey');
        $authToken=$this->getAuthToken();
        $appId=Config::get('getui.appid');
        $content=[
            'message'=>[
                "appkey"=>$appKey,
                "is_offline"=>false,
                "msgtype"=>"notification"
            ],
            'notification'=>[
                'style'=>[
                    'type'=>1,
                    'text'=>$content['text'],
                    'title'=>$content['title'],
                    'logourl'=>$content['logourl'],
                    'is_ring'=>$content['is_ring'],
                    'is_vibrate'=>$content['is_vibrate'],
                    'is_clearable'=>$content['is_clearable'],
                ],
                "transmission_type"=>true,
                "transmission_content"=>$transmission_content
            ],
            'requestid'=>"".time(),
        ];
        $content=json_encode($content);
        $header=[
            'Content-Type: application/json',
            'authtoken:'.$authToken
        ];
        $url='https://restapi.getui.com/v1/'.$appId.'/push_app';
        //
        $res=curl_post_json($url,$header,$content);
        $res=json_decode($res,true);
        // 将结果存储到redis中
        $this->cache_getui_res($res);
        return $res;
    }
    /**
     *  群发消息
     *  - 向cidList中的cid发送消息
     *  - 需要调用两次接口,分别是save_list_body 和 push_list
     * @param $cidList array
     * @param $content
     * @param $transmission_content string
     * @return array
     */
    public function sendToListNotification($cidList=[],$content,$transmission_content=''){
        $appKey=Config::get('getui.appkey');
        $authToken=$this->getAuthToken();
        $appId=Config::get('getui.appid');
        $content=array(
            'message'=>[
                "appkey"=>$appKey,
                "is_offline"=>false,
                "msgtype"=>"notification"
            ],
            'notification'=>[
            'style'=>[
                'type'=>1,
                'text'=>$content['text'],
                'title'=>$content['title'],
                'logourl'=>$content['logourl'],
                'is_ring'=>$content['is_ring'],
                'is_vibrate'=>$content['is_vibrate'],
                'is_clearable'=>$content['is_clearable'],
                ],
                "transmission_type"=> true,
                "transmission_content"=> $transmission_content
            ],
        );
        $content=json_encode($content);
        $header=array(
            'Content-Type: application/json',
            'authtoken:'.$authToken
        );
        // 首先进行要发送的内容的保存
        $url='https://restapi.getui.com/v1/'.$appId.'/save_list_body ';
        // 成功之后获取taskid
        $res=curl_post_json($url,$header,$content);
        $res=json_decode($res,true);
        // 将结果存储到redis中
        $this->cache_getui_res($res);
        if($res['result']=='ok'){
            // 调用tolist接口
            $toListContent=[
                'cid'=>$cidList,
                'taskid'=>$res['taskid'],
                'need_detail'=>false,
            ];
            $toListContent=json_encode($toListContent);
            $url='https://restapi.getui.com/v1/'.$appId.'/push_list ';
            $res=curl_post_json($url,$header,$toListContent);
            $res=json_decode($res,true);
            // 将结果存储到redis中
            $this->cache_getui_res($res);
            return $res;
        }else{
            // 将结果存储到redis中
            $this->cache_getui_res($res);
            return $res;
        }
    }

    /**
     * 用于本地缓存个推API调用的结果
     * - 可以用于查看API调用的具体情况
     * - 本地缓存的key是 getui_res_list 
     * @param $res
     */
    protected function cache_getui_res($res){
        try{
            $nowList=Cache::get('getui_res_list');
            $arr=['res'=>$res,'time'=>date('Y-m-d H:i:s',time())];
            if(is_array($nowList)){
                array_push($nowList,$arr);
                // 如果已经数组了 则世界array_push
                Cache::set('getui_res_list',$nowList);
            }else{
                Cache::set('getui_res_list',[0=>$arr]);
            }
        }catch (\Exception $exception){

        }
    }
}