一. 前言:
上篇小熙介绍了信鸽推送,这篇继续分享下极光推送的集成。
极光推送是第三方推送平台,部分免费的第三方消息推送服务,目前各方面都还不错。极光推送让开发者可以即时地向其应用程序的用户推送通知或消息,与用户保持互动,从而有效地提高留存率。官方整合了Android推送、iOS推送的统一推送服务,发送用户的指定范围也是有很多全面的选择,等等其他更好功能的选择。
极光官网
二. 视图:
展示图:
三. 依赖:
极光官网依赖坐标:
<!-- 极光推送 -->
<dependency>
<groupId>cn.jpush.api</groupId>
<artifactId>jpush-client</artifactId>
<version>3.4.3</version>
</dependency>
四. 官网摘录:
-
audience:推送目标
推送设备对象,表示一条推送可以被推送到哪些设备列表。确认推送设备对象,JPush 提供了多种方式,比如:别名、标签、注册 ID、分群、广播等。
all
如果要发广播(全部设备),则直接填写 “all”。基于业务优化的需求,极光将于 3 月 10 日对「广播推送」的频率进行限制,调整为 10 次每天,超过调用限制时将返回报错码 2008,官网控制台将与 Push API 同步调整。
注意:本次调整仅限制广播,对广播外的推送不影响。如广播推送需更高频率,请联系商务,详情请阅读公告。
关键字 类型 含义 说明 备注 tag JSON Array 标签OR 数组。多个标签之间是 OR 的关系,即取并集。 用标签来进行大规模的设备属性、用户属性分群。 一次推送最多 20 个。 - 有效的 tag 组成:字母(区分大小写)、数字、下划线、汉字、特殊字符@!#$&*+=.|¥。
- 限制:每一个 tag 的长度限制为 40 字节。(判断长度需采用 UTF-8 编码)
tag_and JSON Array 标签AND 数组。多个标签之间是 AND 关系,即取交集。 注意与 tag 区分。一次推送最多 20 个。 tag_not JSON Array 标签NOT 数组。多个标签之间,先取多标签的并集,再对该结果取补集。 一次推送最多 20 个。 alias JSON Array 别名 数组。多个别名之间是 OR 关系,即取并集。 用别名来标识一个用户。一个设备只能绑定一个别名,但多个设备可以绑定同一个别名。一次推送最多 1000 个。 - 有效的 alias 组成:字母(区分大小写)、数字、下划线、汉字、特殊字符@!#$&*+=.|¥。
- 限制:每一个 alias 的长度限制为 40 字节。(判断长度需采用 UTF-8 编码)
registration_id JSON Array 注册ID 数组。多个注册 ID 之间是 OR 关系,即取并集。 设备标识。一次推送最多 1000 个。客户端集成 SDK 后可获取到该值。如果您一次推送的 registration_id 值超过 1000 个,可以直接使用 文件推送 功能。 segment JSON Array 用户分群 ID 在页面创建的用户分群的 ID。定义为数组,但目前限制一次只能推送一个。 目前限制是一次只能推送一个。 abtest JSON Array A/B Test ID 在页面创建的 A/B 测试的 ID。定义为数组,但目前限制是一次只能推送一个。 目前限制一次只能推送一个。
五. 配置代码:
-
yml中的数据:
# 极光推送 (true表示生产,false表示开发) jpush: environment: false appKey: d88ba5384916a5c839xxxxxxx masterSecret: 1d6cb3e961ec5d360xxxxxx
-
拓展信息封装类:
package com.chengxi.datalom.utils.jPush; import lombok.Data; import lombok.experimental.Accessors; /** * 极光拓展字段不能传输object,限制了类型,所以封装更好些 * 此类为极光推送拓展字段封装类(目前字段是暂定,你也可以拓展) * * @author chengxi * @date 2020/12/9 14:08 */ @Data @Accessors(chain = true) public class JPushVO { private Long id; private String userName; private String content; }
-
抽象工具父类:
package com.chengxi.datalom.utils.jPush; import cn.jiguang.common.resp.APIConnectionException; import cn.jiguang.common.resp.APIRequestException; import cn.jpush.api.JPushClient; import cn.jpush.api.push.PushResult; import cn.jpush.api.push.model.Message; import cn.jpush.api.push.model.Options; import cn.jpush.api.push.model.Platform; import cn.jpush.api.push.model.PushPayload; import cn.jpush.api.push.model.audience.Audience; import cn.jpush.api.push.model.notification.AndroidNotification; import cn.jpush.api.push.model.notification.IosAlert; import cn.jpush.api.push.model.notification.IosNotification; import cn.jpush.api.push.model.notification.Notification; import com.alibaba.fastjson.JSON; import com.chengxi.datalom.config.jPush.JPushConfig; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; /** * 程熙cjp:https://blog.csdn.net/weixin_41133233 * 极光抽象推送工具类 * * @author chengxi * @date 2020/12/9 16:06 */ @Slf4j @Component public abstract class AbstractJPushToolUtil { @Autowired private JPushConfig jPush; protected static AbstractJPushToolUtil abstractJPushToolUtils; @PostConstruct public void init() { abstractJPushToolUtils = this; } /** * 获取JPushClient实例 * * @return */ private static JPushClient getJPushClient() { JPushClient jPushClient = new JPushClient(abstractJPushToolUtils.jPush.getMasterSecret(), abstractJPushToolUtils.jPush.getAppKey()); return jPushClient; } /** * 获取推送创建build * * @param platform * @param audience * @param offlineSaveSeconds * @param msgTitle * @param msgContent * @param jPushVO * @param sendNo * @return */ protected static PushPayload.Builder queryPushPayloadBuilder(Platform platform, Audience audience, Long offlineSaveSeconds, String msgTitle, String msgContent, JPushVO jPushVO, Integer sendNo) { return PushPayload.newBuilder() //指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android、ios等具体平台 .setPlatform(platform) //指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id .setAudience(audience) //Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息, // sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的 // [通知与自定义消息有什么区别?]了解通知和自定义消息的区别 .setMessage(Message.newBuilder().setTitle(msgTitle).setMsgContent(msgContent).addExtra("data", JSON.toJSONString(jPushVO)).build()) .setOptions(Options.newBuilder() //此字段的值是用来指定本推送要推送的apns环境,true表示生产,false表示开发;对android和自定义消息无意义 .setApnsProduction(abstractJPushToolUtils.jPush.getEnvironment()) //此字段是给开发者自己给推送编号,方便推送者分辨推送记录,默认为1 .setSendno(sendNo == null ? 1 : sendNo) //此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天,单位为秒 .setTimeToLive(offlineSaveSeconds) .build()); } /** * 发送给所有用户(目前默认安卓和ios) * * @param audience * @param offlineSaveSeconds * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @param sendNo * @return */ public static boolean sendToAll(Audience audience, Long offlineSaveSeconds, String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, Integer sendNo) { boolean result = false; try { PushPayload pushPayload = queryPushPayloadBuilder(Platform.android_ios(), audience, offlineSaveSeconds, msgTitle, msgContent, null, sendNo) .setNotification(Notification.newBuilder() //指定当前推送的android通知 .addPlatformNotification(queryAndroidNotification(notificationTitle, msgContent, jPushVO)) //指定当前推送的ios通知 .addPlatformNotification(queryIosNotification(queryIosAlert(notificationTitle, msgContent, msgContent), jPushVO)) .build()) .build(); PushResult pushResult = getJPushClient().sendPush(pushPayload); if (pushResult.getResponseCode() == 200) { result = true; } log.info("[极光推送]PushResult result is " + pushResult); } catch (APIConnectionException e) { log.error("[极光推送]Connection error. Should retry later. ", e); } catch (APIRequestException e) { log.error("[极光推送]Error response from JPush server. Should review and fix it. ", e); printAPIRequestErrorLogInfo(e); } return result; } /** * 发送给安卓用户 * * @param audience * @param offlineSaveSeconds * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @return */ public static boolean sendToAndroid(Audience audience, Long offlineSaveSeconds, String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, Integer sendNo) { boolean result = false; try { PushPayload pushPayload = queryPushPayloadBuilder(Platform.android(), audience, offlineSaveSeconds, msgTitle, msgContent, null, sendNo) .setNotification(Notification.newBuilder() //指定当前推送的android通知 .addPlatformNotification(queryAndroidNotification(notificationTitle, msgContent, jPushVO)) .build()) .build(); PushResult pushResult = getJPushClient().sendPush(pushPayload); if (pushResult.getResponseCode() == 200) { result = true; } log.info("[极光推送]PushResult result is " + pushResult); } catch (APIConnectionException e) { log.error("[极光推送]Connection error. Should retry later. ", e); } catch (APIRequestException e) { log.error("[极光推送]Error response from JPush server. Should review and fix it. ", e); printAPIRequestErrorLogInfo(e); } return result; } /** * 发送给IOS用户 * * @param audience * @param offlineSaveSeconds * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @return */ public static boolean sendToIos(Audience audience, Long offlineSaveSeconds, String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, Integer sendNo) { boolean result = false; try { PushPayload pushPayload = queryPushPayloadBuilder(Platform.ios(), audience, offlineSaveSeconds, msgTitle, msgContent, jPushVO, sendNo) .setNotification(Notification.newBuilder() //指定当前推送的Ios通知 // .addPlatformNotification(builder.build()).build()) .addPlatformNotification(queryIosNotification(queryIosAlert(notificationTitle, msgTitle, msgContent), jPushVO)) .build()) .build(); PushResult pushResult = getJPushClient().sendPush(pushPayload); if (pushResult.getResponseCode() == 200) { result = true; } log.info("[极光推送]PushResult result is " + pushResult); } catch (APIConnectionException e) { log.error("[极光推送]Connection error. Should retry later. ", e); } catch (APIRequestException e) { log.error("[极光推送]Error response from JPush server. Should review and fix it. ", e); printAPIRequestErrorLogInfo(e); } return result; } /** * 打印APIRequestErrorLogInfo * * @param e */ private static void printAPIRequestErrorLogInfo(APIRequestException e) { log.info("[极光推送]HTTP Status: " + e.getStatus()); log.info("[极光推送]Error Code: " + e.getErrorCode()); log.info("[极光推送]Error Message: " + e.getErrorMessage()); } /** * AndroidNotification * * @param notificationTitle * @param msgContent * @param jPushVO * @return */ private static AndroidNotification queryAndroidNotification(String notificationTitle, String msgContent, JPushVO jPushVO) { return AndroidNotification.newBuilder() .setTitle(notificationTitle) .setAlert(msgContent) //此字段为透传字段(类型被极光限定,不能传object),不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value) .addExtra("data", JSON.toJSONString(jPushVO)) .build(); } /** * 获取IosNotificationBuilder * * @param iosAlert * @param jPushVO * @return */ private static IosNotification queryIosNotification(IosAlert iosAlert, JPushVO jPushVO) { return IosNotification.newBuilder() //ios不支持直接设置title,你可以传一个IosAlert对象哪里再解析,指定apns title、title、subtitle(这里的key参考官方文档)等 // .setAlert(IosAlert.newBuilder().setTitleAndBody(notificationTitle, null, msgContent).build()) .setAlert(iosAlert) //直接传alert //此项是指定此推送的badge自动加1 .incrBadge(1) // .setBadge(+1) //此字段的值default表示系统默认声音;传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒, // 如果系统没有此音频则以系统默认声音提醒;此字段如果传空字符串,iOS9及以上的系统是无声音提醒,以下的系统是默认声音 .setSound("sound.caf") // .setSound("happy") //此字段为透传字段(类型被极光限定,不能传object),不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value) .addExtra("data", JSON.toJSONString(jPushVO)) //此项说明此推送是一个background推送,想了解background看:http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification // .setContentAvailable(true) .build(); } /** * 获取IOS的IosAlert * * @param notificationTitle * @param subTitle * @param msgContent * @return */ private static IosAlert queryIosAlert(String notificationTitle, String subTitle, String msgContent) { return IosAlert.newBuilder().setTitleAndBody(notificationTitle, subTitle, msgContent).build(); } /** * 获取IOS的IosAlert * * @param notificationTitle * @param msgContent * @return */ private static IosAlert queryIosAlert(String notificationTitle, String msgContent) { return queryIosAlert(notificationTitle, null, msgContent); } }
-
使用工具类:
package com.chengxi.datalom.utils.jPush; import cn.jpush.api.push.model.audience.Audience; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import java.util.List; /** * 程熙cjp:https://blog.csdn.net/weixin_41133233 * 极光推送工具类 * audience 类型还有很多用法,这里是基础的可以根据需要发送的范围进行修改。更多拓展请参考官网。 * 请参考官网详细说明:http://docs.jiguang.cn/jpush/server/push/rest_api_v3_push/#audience * * @author chengxi * @date 2020/12/9 15:53 */ @Slf4j @Component public class JPushToolUtil extends AbstractJPushToolUtil { /** * 发送给所有用户(默认安卓和ios端) * * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @return */ public static boolean sendToAll(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO) { return sendToAll(Audience.all(), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } /** * 发送给批量(别名)用户(默认安卓和ios端) * * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @param aliasList * @return */ public static boolean sendToAliasListAll(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, List<String> aliasList) { return sendToAll(Audience.alias(aliasList), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } /** * 发送给批量(标签)用户(默认安卓和ios端) * * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @param tagList * @return */ public static boolean sendToTagListAll(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, List<String> tagList) { return sendToAll(Audience.tag(tagList), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } /** * 发送给批量(不在标签集合中的)用户(默认安卓和ios端) * * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @param tagNotList * @return */ public static boolean sendToNotTagListAll(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, List<String> tagNotList) { return sendToAll(Audience.tag_not(tagNotList), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } /** * 发送给所有安卓用户(默认全部并且保留离线保存时长为一天) * * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @return */ public static boolean sendToAllAndroid(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO) { return sendToAndroid(Audience.all(), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } /** * 发送给批量(别名)安卓用户(默认全部并且保留离线保存时长为一天) * * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @param aliasList * @return */ public static boolean sendToAliasListAndroid(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, List<String> aliasList) { return sendToAndroid(Audience.alias(aliasList), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } /** * 发送给批量(标签中的)安卓用户(默认全部并且保留离线保存时长为一天) * * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @param tagList * @return */ public static boolean sendToTagListAndroid(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, List<String> tagList) { return sendToAndroid(Audience.tag(tagList), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } /** * 发送给批量(不在标签中的)安卓用户(默认全部并且保留离线保存时长为一天) * * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @param tagNotList * @return */ public static boolean sendToNotTagListAndroid(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, List<String> tagNotList) { return sendToAndroid(Audience.tag(tagNotList), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } /** * 发送给所有ios用户(默认全部并且保留离线保存时长为一天) * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @return */ public static boolean sendToAllIos(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO) { return sendToIos(Audience.all(), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } /** * 发送给批量(别名)ios用户(默认全部并且保留离线保存时长为一天) * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @return */ public static boolean sendToAliasListIos(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, List<String> aliasList) { return sendToIos(Audience.alias(aliasList), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } /** * 发送给批量(标签中的)ios用户(默认全部并且保留离线保存时长为一天) * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @param tagList * @return */ public static boolean sendToTagListIos(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, List<String> tagList) { return sendToIos(Audience.tag(tagList), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } /** * 发送给批量(不在标签中的)ios用户(默认全部并且保留离线保存时长为一天) * @param notificationTitle * @param msgTitle * @param msgContent * @param jPushVO * @param tagNotList * @return */ public static boolean sendToNotTagListIos(String notificationTitle, String msgTitle, String msgContent, JPushVO jPushVO, List<String> tagNotList) { return sendToIos(Audience.tag(tagNotList), 86400L, notificationTitle, msgTitle, msgContent, jPushVO, null); } }
六. 示例:
下面是小熙的测试用例:
@Test
public void testJPush() {
JPushVO pushVO = new JPushVO();
pushVO.setId(1L);
pushVO.setUserName("程熙");
pushVO.setContent("My name is Xiao Xi");
System.err.println(JPushToolUtil.sendToAll("通知标题", "消息标题", "消息内容", pushVO));
}
七. 后语:
至此小熙就分享完后端集成极光推送了,前端集成也是还需要按照官网流程操作生成应用,获取对应key,想实现更多功能还是建议多看看官方文档。他的玩法和示例比信鸽要全很多。