笔者最近有个需求:pc端创建任务后需要实时下发到app端,即安装app的用户在任务创建之后能实时收到通知。


因为项目一直是基于uni-app开发的,故利用个推的开发文档进行开发

话不多说,直接开干:

STEP1:登录个推开发者中心,注册应用,获取AppID、AppKey、MasterSecret等参数。点此查看操作说明,如果是DCloud uniPush的用户,获取AppID、AppKey、MasterSecret等信息请参考DCloud文档

STEP2:集成服务端SDK,点此查看集成指南

<dependencies>
		<!--unipush-->
		<dependency>
            <groupId>com.gexin.platform</groupId>
            <artifactId>gexin-rp-sdk-base</artifactId>
            <version>4.0.0.30</version>
        </dependency>
        <dependency>
            <groupId>com.gexin.platform</groupId>
            <artifactId>gexin-rp-sdk-template</artifactId>
            <version>4.0.0.24</version>
        </dependency>
        <dependency>
            <groupId>com.gexin.platform</groupId>
            <artifactId>gexin-rp-sdk-http</artifactId>
            <version>4.1.0.5</version>
        </dependency>
        <dependency>
            <groupId>com.gexin.platform</groupId>
            <artifactId>gexin-rp-fastjson</artifactId>
            <version>1.0.0.3</version>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>2.5.0</version>
        </dependency>
</dependencies>

 <repositories>
        <repository>
            <id>getui-nexus</id>
            <url>http://mvn.gt.getui.com/nexus/content/repositories/releases/</url>
        </repository>
    </repositories>

STEP3:查看接口说明,按需调用
笔者使用的是【toList】执行批量推

  1. 先定义实体bo
public class PushStyle {
    private String title;//通知栏标题
    private String text;//通知栏内容
    private String logo;//通知的图标名称,包含后缀名(需要在客户端开发时嵌入),如“icon.png”小LOGO,默认push_small.png,需要提前内置到客户端
    private String logoUrl;//通知栏网络图标
    private String channel;//通知渠道id
    private String channelName;//通知渠道名称
    private Integer channelLevel;//通知渠道重要性 具体值有0、1、2、3、4;设置之后不能修改;具体展示形式如下:0:无声音,无震动,不显示。(不推荐)
                                //1:无声音,无震动,锁屏不显示,通知栏中被折叠显示,导航栏无logo。
                                //2:无声音,无震动,锁屏和通知栏中都显示,通知不唤醒屏幕。
                                //3:有声音,有震动,锁屏和通知栏中都显示,通知唤醒屏幕。(推荐)
                                //4:有声音,有震动,亮屏下通知悬浮展示,锁屏通知以默认形式展示且唤醒屏幕。(推荐)

    //以下两种方式选一种
    private String bigImageUrl;//通知展示大图样式,参数是大图的URL地址
    private String bigText;//通知展示文本+长文本样式,参数是长文本

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getLogo() {
        return logo;
    }

    public void setLogo(String logo) {
        this.logo = logo;
    }

    public String getLogoUrl() {
        return logoUrl;
    }

    public void setLogoUrl(String logoUrl) {
        this.logoUrl = logoUrl;
    }

    public String getChannel() {
        return channel;
    }

    public void setChannel(String channel) {
        this.channel = channel;
    }

    public String getChannelName() {
        return channelName;
    }

    public void setChannelName(String channelName) {
        this.channelName = channelName;
    }

    public Integer getChannelLevel() {
        return channelLevel;
    }

    public void setChannelLevel(Integer channelLevel) {
        this.channelLevel = channelLevel;
    }

    public String getBigImageUrl() {
        return bigImageUrl;
    }

    public void setBigImageUrl(String bigImageUrl) {
        this.bigImageUrl = bigImageUrl;
    }

    public String getBigText() {
        return bigText;
    }

    public void setBigText(String bigText) {
        this.bigText = bigText;
    }

    /*设定默认值*/
    public PushStyle() {
        this.logoUrl="";
        this.channel = "Default";
        this.channelName = "Default";
        this.channelLevel = 3;
        this.bigImageUrl="";
        this.bigText="";
    }
}

2.然后定义一个配置类

@Configuration
public class PushConfig {
    public static String appId;

    public static String appKey;

    public static String masterSecret;

    public static String host;

    public static long offlineExpireTime;//过多久该消息离线失效(单位毫秒) 支持1-72小时*3600000毫秒

    @Value("${spring.push.appId}")
    public void setAppId(String appId) {
        PushConfig.appId = appId;
    }

    @Value("${spring.push.appKey}")
    public void setAppKey(String appKey) {
        PushConfig.appKey = appKey;
    }

    @Value("${spring.push.masterSecret}")
    public void setMasterSecret(String masterSecret) {
        PushConfig.masterSecret = masterSecret;
    }

    @Value("${spring.push.host}")
    public void setHost(String host) {
        PushConfig.host = host;
    }

    @Value("${spring.push.offlineExpireTime}")
    public void setOfflineExpireTime(long offlineExpireTime) {
        PushConfig.offlineExpireTime = offlineExpireTime;
    }
}

3.接着定义一个工具类

@Component
public class PushHelper {

    /**
     * 批量推送
     * @param pushStyle 通知样式
     * @param appPushList 通知范围 存储clientId字符串
     */
    public void pushMessage(PushStyle pushStyle, List<String> appPushList) {
        System.setProperty("gexin_pushList_needDetails", "true");
        IGtPush push = new IGtPush(PushConfig.host, PushConfig.appKey, PushConfig.masterSecret);
        NotificationTemplate template = getNotificationTemplate(pushStyle);
        // 采用toList方案,定义ListMessage消息类型
        ListMessage message = new ListMessage();
        message.setData(template);
        message.setOffline(true);
        message.setOfflineExpireTime(PushConfig.offlineExpireTime);  // 时间单位为毫秒
        String contentId = push.getContentId(message);
        // 获取推送目标
        List targets = new ArrayList();//推送目标列表,单次推送数量限制1000以内
        for (String ap : appPushList) {
            Target target = new Target();
            target.setAppId(PushConfig.appId);
            target.setClientId(ap);
            targets.add(target);
        }
        IPushResult ret = push.pushMessageToList(contentId, targets);
        System.out.println(ret.getResponse().toString());
    }

    /**
     * 群推-即所有安装app的可执行用户
     * 注:也可以设定筛选条件,择出符合要求的推送用户
     * @param pushStyle 通知样式
     */
    public void pushToApp(PushStyle pushStyle) {
        System.setProperty("gexin_pushList_needDetails", "true");
        IGtPush push = new IGtPush(PushConfig.host, PushConfig.appKey, PushConfig.masterSecret);
        NotificationTemplate template = getNotificationTemplate(pushStyle);
        // 采用toApp方案,AppMessage
        List<String> appIds = new ArrayList<String>();
        appIds.add(PushConfig.appId);
        AppMessage message = new AppMessage();
        message.setData(template);
        message.setAppIdList(appIds);
        message.setOffline(true);
        message.setOfflineExpireTime(PushConfig.offlineExpireTime);  // 时间单位为毫秒
        //执行推送
        IPushResult ret = push.pushMessageToApp(message);
        System.out.println(ret.getResponse().toString());
    }

    //配置通知模板
    private static NotificationTemplate getNotificationTemplate(PushStyle pushStyle) {
        NotificationTemplate template = new NotificationTemplate();
        // 设置APPID与APPKEY
        template.setAppId(PushConfig.appId);
        template.setAppkey(PushConfig.appKey);

        if(StringUtil.isEmpty(pushStyle.getBigImageUrl()) && StringUtil.isEmpty(pushStyle.getBigText())) {//系统样式
            Style0 style = new Style0();
            // 设置通知栏标题与内容
            style.setTitle(pushStyle.getTitle());
            style.setText(pushStyle.getText());
            // 配置通知栏图标
//        style.setLogo("icon.png");
            // 配置通知栏网络图标
            style.setLogoUrl(pushStyle.getLogoUrl());
            // 设置通知是否响铃,震动,或者可清除
            style.setRing(true);
            style.setVibrate(true);
            style.setClearable(true);
            style.setChannel(pushStyle.getChannel());
            style.setChannelName(pushStyle.getChannelName());
            style.setChannelLevel(pushStyle.getChannelLevel()); //设置通知渠道重要性
            template.setStyle(style);
        }else{//大图+文本样式
            Style6 style = new Style6();
            style.setTitle(pushStyle.getTitle());
            style.setText(pushStyle.getText());
            style.setLogoUrl(pushStyle.getLogoUrl());
            style.setBigStyle1(pushStyle.getBigImageUrl());
            style.setBigStyle2(pushStyle.getBigText());
            style.setRing(true);
            style.setVibrate(true);
            style.setClearable(true);
            style.setChannel(pushStyle.getChannel());
            style.setChannelName(pushStyle.getChannelName());
            style.setChannelLevel(pushStyle.getChannelLevel());
            template.setStyle(style);
        }

        template.setTransmissionType(1);  // 透传消息接受方式设置,1:立即启动APP,2:客户端收到消息后需要自行处理
        template.setTransmissionContent(JSONObject.fromObject(pushStyle).toString());

        //template.setAPNInfo(getAPNPayload()); //详见【推送模板说明】iOS通知样式设置
        return template;
    }
}

4.最后就是调用了

@RequestMapping("/getTest")
    @ResponseBody
    @ApiOperation(value = "测试app端消息推送接口", response = ResponseResult.class)
    @ApiVersion(group = ApiVersionConstant.EDU_SYSTEM_MANAGEMENT_VERSION_1_0)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "access_token", paramType = "query", value = "认证", required = true, dataType = "String")})
    public void getTest(){
        try {
            PushStyle style=new PushStyle();
            style.setTitle("这是一个标题");
            style.setText("这是一条信息推送测试!");
            List<String> list=new ArrayList<>();
            list.add("41281d5b190321fdccd91fffc820b729");
            list.add("a425be5fe63ce8a410cccd816cf215d8");
            pushHelper.pushMessage(style,list);
        } catch (Exception e) {
            logger.error("测试app端消息推送{}",e.getMessage());
            e.printStackTrace();
        }
    }

到此在线app消息推送完毕,或许有人要问离线怎么办?笔者也正在研究,待研究好了再来与大家一起探讨。

注:笔者在开发时遇到的问题

1.调用IGtPush push = new IGtPush(host, appKey, masterSecret)方法报错:

Can not get hosts from [http://sdk.open.api.igexin.com/serviceex, http://sdk.open.api.gepush.com/serviceex,http://sdk.open.api.getui.net/serviceex]

出现原因:配置文件读取属性出错,值为空

2.执行 String contentId = push.getContentId(message)方法报空指针

出现原因:Style0对象中属性setLogoUrl,channel,channelName值可以为空但是不能为null