1 极光推送的核心类如下:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.assertj.core.util.Strings;
import pre.cyy.download.HttpClientDownloader;
import pre.cyy.request.*;
import pre.cyy.utils.HttpConstant;
import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.List;
import java.util.Objects;
/**
* @Author: yang
* @Date: 2018/6/13.10:50
* @Desc: JPush 极光推送
*/
public final class JPush {
// 加密后的base64字符串
private static String Authorization;
//推送对象
private static JPush J_PUSH;
//DOWNLOADER
private static final HttpClientDownloader DOWNLOADER = new HttpClientDownloader();
private JPush() {
}
/**
* @Author yang
* @Date 2018/6/13 14:40
* @Description 获取推送实例
*/
public static JPush getInstance() {
if (J_PUSH == null) {
synchronized (JPush.class) {
if (J_PUSH == null) {
try {
Authorization = Base64.getEncoder().encodeToString(JPushConfig.AUTHORIZATION_PARM.getBytes("utf-8"));
} catch (UnsupportedEncodingException e) {
//秘钥转换失败
throw new IllegalArgumentException("秘钥转换失败 检查秘钥参数 ");
} finally {
J_PUSH = new JPush();
}
}
}
}
return J_PUSH;
}
/**
* @Author yang
* @Date 2018/6/13 11:35
* @Description 转换data
*/
public JPushData convertData(JPushBuilder jPushBuilder) {
JPushData data = new JPushData();
//不存在cid 自动生成一个cid
if (!Strings.isNullOrEmpty(jPushBuilder.getCid())) {
data.setCid(jPushBuilder.getCid());
} else {
data.setCid(autoGenerateCid());
}
if (Objects.nonNull(jPushBuilder.getAudience())) {
data.setAudience(jPushBuilder.getAudience());
}
if (Objects.nonNull(jPushBuilder.getMessage())) {
data.setMessage(jPushBuilder.getMessage());
}
if (Objects.nonNull(jPushBuilder.getNotification())) {
data.setNotification(jPushBuilder.getNotification());
}
if (Objects.nonNull(jPushBuilder.getOptions())) {
data.setOptions(jPushBuilder.getOptions());
}
if (Objects.nonNull(jPushBuilder.getPlatform())) {
data.setPlatform(jPushBuilder.getPlatform());
}
if (Objects.nonNull(jPushBuilder.getSms_message())) {
data.setSms_message(jPushBuilder.getSms_message());
}
return data;
}
/**
* @Author yang
* @Date 2018/6/13 13:43
* @Description 自动生成cid
*/
public String autoGenerateCid() {
//设置请求的编码 超时时间5s
Task task = Site.me()
.setTimeOut(5000)
.addHeader("Authorization", "Basic " + Authorization)
.addHeader("Content-Type", "application/json")
.setCharset("utf-8")
.toTask();
Request request = new Request();
request.setUrl(JPushConfig.CID_URL);
request.setMethod(HttpConstant.Method.GET);
List cidList;
try {
Page page = DOWNLOADER.download(request, task);
if (page.getStatusCode() == 200) {
JSONObject jsonObject = JSON.parseObject(page.getRawText());
cidList = JSON.parseArray(jsonObject.getString("cidlist"), String.class);
} else {
throw new IllegalArgumentException("cid 获取接口请求失败 失败原因" + page.getRawText());
}
} catch (Exception e) {
return null;
}
return cidList.get(0);
}
/**
* @Author yang
* @Date 2018/6/13 11:35
* @Description 执行推送操作
*/
public Page push(JPushData data) {
//设置请求的编码 超时时间5s
Task task = Site.me()
.setTimeOut(5000)
.addHeader("Authorization", "Basic " + Authorization)
.addHeader("Content-Type", "application/json")
.setCharset("utf-8")
.toTask();
Request request = new Request();
request.setUrl(JPushConfig.PUSH_URL);
request.setMethod(HttpConstant.Method.POST);
try {
request.setRequestBody(HttpRequestBody.json(JSON.toJSONString(data), "utf-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return DOWNLOADER.download(request, task);
}
}
2 极光推送的数据实体 方便构造 json 传递给极光api
import org.apache.commons.collections.map.HashedMap;
import java.util.List;
/**
* @Author: yang
* @Date: 2018/6/13.10:54
* @Desc: JPushData 推送的数据
*/
public class JPushData {
//cid cid 是用于防止 api 调用端重试造成服务端的重复推送而定义的一个推送参数。
// 用户使用一个 cid 推送后,再次使用相同的 cid 进行推送,则会直接返回第一次成功推送的结果,不会再次进行推送。
private String cid;
// 推送到所有平台: { "platform" : "all" } 指定特定推送平台: { "platform" : ["android", "ios"] }
private String platform;
// audience:推送目标 推送设备对象, 提供了多种方式,比如:别名、标签、注册ID、分群、广播等。 如果要发广播(全部设备),则直接填写 “all”。
private AudienceBean audience;
//通知对象 ios Android
private NotificationBean notification;
//自定义消息类型 不会显示在前台 需要app 自行处理数据
private MessageBean message;
//暂时用不到
private SmsMessageBean sms_message;
//options:可选参数
private OptionsBean options;
public String getCid() {
return cid;
}
public void setCid(String cid) {
this.cid = cid;
}
public String getPlatform() {
return platform;
}
public void setPlatform(String platform) {
this.platform = platform;
}
public AudienceBean getAudience() {
return audience;
}
public void setAudience(AudienceBean audience) {
this.audience = audience;
}
public NotificationBean getNotification() {
return notification;
}
public void setNotification(NotificationBean notification) {
this.notification = notification;
}
public MessageBean getMessage() {
return message;
}
public void setMessage(MessageBean message) {
this.message = message;
}
public SmsMessageBean getSms_message() {
return sms_message;
}
public void setSms_message(SmsMessageBean sms_message) {
this.sms_message = sms_message;
}
public OptionsBean getOptions() {
return options;
}
public void setOptions(OptionsBean options) {
this.options = options;
}
public static class AudienceBean {
private List tag;
private List registration_id;
public List getTag() {
return tag;
}
public void setTag(List tag) {
this.tag = tag;
}
public List getRegistration_id() {
return registration_id;
}
public void setRegistration_id(List registration_id) {
this.registration_id = registration_id;
}
}
public static class NotificationBean {
/**
* android : {"alert":"Hi, JPush!","title":"Send to Android","builder_id":1,"extras":{"newsid":321}}
* ios : {"alert":"Hi, JPush!","sound":"default","badge":"+1","extras":{"newsid":321}}
*/
private AndroidBean android;
private IosBean ios;
public AndroidBean getAndroid() {
return android;
}
public void setAndroid(AndroidBean android) {
this.android = android;
}
public IosBean getIos() {
return ios;
}
public void setIos(IosBean ios) {
this.ios = ios;
}
public static class AndroidBean {
/**
* alert : Hi, JPush!
* title : Send to Android
* builder_id : 1
* extras : {"newsid":321}
*/
private String alert;
private String title;
private int builder_id;
private ExtrasBean extras;
public String getAlert() {
return alert;
}
public void setAlert(String alert) {
this.alert = alert;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getBuilder_id() {
return builder_id;
}
public void setBuilder_id(int builder_id) {
this.builder_id = builder_id;
}
public ExtrasBean getExtras() {
return extras;
}
public void setExtras(ExtrasBean extras) {
this.extras = extras;
}
public static class ExtrasBean {
private HashedMap extras;
public HashedMap getExtras() {
return extras;
}
public void setExtras(HashedMap extras) {
this.extras = extras;
}
}
}
public static class IosBean {
/**
* alert : Hi, JPush!
* sound : default
* badge : +1
* extras : {"newsid":321}
*/
private String alert;
private String sound;
private String badge;
private ExtrasBeanX extras;
public String getAlert() {
return alert;
}
public void setAlert(String alert) {
this.alert = alert;
}
public String getSound() {
return sound;
}
public void setSound(String sound) {
this.sound = sound;
}
public String getBadge() {
return badge;
}
public void setBadge(String badge) {
this.badge = badge;
}
public ExtrasBeanX getExtras() {
return extras;
}
public void setExtras(ExtrasBeanX extras) {
this.extras = extras;
}
public static class ExtrasBeanX {
private HashedMap extras;
public HashedMap getExtras() {
return extras;
}
public void setExtras(HashedMap extras) {
this.extras = extras;
}
}
}
}
public static class MessageBean {
/**
* msg_content : Hi,JPush
* content_type : text
* title : msg
* extras : {"key":"value"}
*/
private String msg_content;
private String content_type;
private String title;
private ExtrasBeanXX extras;
public String getMsg_content() {
return msg_content;
}
public void setMsg_content(String msg_content) {
this.msg_content = msg_content;
}
public String getContent_type() {
return content_type;
}
public void setContent_type(String content_type) {
this.content_type = content_type;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public ExtrasBeanXX getExtras() {
return extras;
}
public void setExtras(ExtrasBeanXX extras) {
this.extras = extras;
}
public static class ExtrasBeanXX {
/**
* key : value
*/
private String key;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
}
}
public static class SmsMessageBean {
/**
* temp_id : 1250
* temp_para : {"code":"123456"}
* delay_time : 3600
*/
private int temp_id;
private TempParaBean temp_para;
private int delay_time;
public int getTemp_id() {
return temp_id;
}
public void setTemp_id(int temp_id) {
this.temp_id = temp_id;
}
public TempParaBean getTemp_para() {
return temp_para;
}
public void setTemp_para(TempParaBean temp_para) {
this.temp_para = temp_para;
}
public int getDelay_time() {
return delay_time;
}
public void setDelay_time(int delay_time) {
this.delay_time = delay_time;
}
public static class TempParaBean {
/**
* code : 123456
*/
private String code;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
}
}
public static class OptionsBean {
/**
* time_to_live : 60
* apns_production : false
* apns_collapse_id : jiguang_test_201706011100
*/
private int time_to_live;
private boolean apns_production;
private String apns_collapse_id;
public int getTime_to_live() {
return time_to_live;
}
public void setTime_to_live(int time_to_live) {
this.time_to_live = time_to_live;
}
public boolean isApns_production() {
return apns_production;
}
public void setApns_production(boolean apns_production) {
this.apns_production = apns_production;
}
public String getApns_collapse_id() {
return apns_collapse_id;
}
public void setApns_collapse_id(String apns_collapse_id) {
this.apns_collapse_id = apns_collapse_id;
}
}
}
3 构建数据 buildr 用于构造一些自定义的参数 很直观的 也是能维持数据的一致性
/**
* @Author: yang
* @Date: 2018/6/13.10:55
* @Desc: JPushBuilder 方便构造推送的数据
*/
public class JPushBuilder {
private String cid;
private String platform;
private JPushData.AudienceBean audience;
private JPushData.NotificationBean notification;
private JPushData.MessageBean message;
private JPushData.SmsMessageBean sms_message;
private JPushData.OptionsBean options;
public JPushBuilder(build build) {
this.cid = build.cid;
this.platform = build.platform;
this.audience = build.audience;
this.notification = build.notification;
this.message = build.message;
this.sms_message = build.sms_message;
this.options = build.options;
}
public String getCid() {
return cid;
}
public String getPlatform() {
return platform;
}
public JPushData.AudienceBean getAudience() {
return audience;
}
public JPushData.NotificationBean getNotification() {
return notification;
}
public JPushData.MessageBean getMessage() {
return message;
}
public JPushData.SmsMessageBean getSms_message() {
return sms_message;
}
public JPushData.OptionsBean getOptions() {
return options;
}
public static class build {
private String cid;
private String platform;
private JPushData.AudienceBean audience;
private JPushData.NotificationBean notification;
private JPushData.MessageBean message;
private JPushData.SmsMessageBean sms_message;
private JPushData.OptionsBean options;
public build setCid(String cid) {
this.cid = cid;
return this;
}
public build setPlatform(String platform) {
this.platform = platform;
return this;
}
public build setAudience(JPushData.AudienceBean audience) {
this.audience = audience;
return this;
}
public build setNotification(JPushData.NotificationBean notification) {
this.notification = notification;
return this;
}
public build setMessage(JPushData.MessageBean message) {
this.message = message;
return this;
}
public build setSms_message(JPushData.SmsMessageBean sms_message) {
this.sms_message = sms_message;
return this;
}
public build setOptions(JPushData.OptionsBean options) {
this.options = options;
return this;
}
public JPushBuilder builder() {
return new JPushBuilder(this);
}
}
}
4. 推送的配置类 一些基础的配置
/**
* @Author: yang
* @Date: 2018/6/13.15:47
* @Desc: JPushConfig 极光配置文件
*/
public class JPushConfig {
//app秘钥
public final static String APPKEY = "";
//MASTER_SECRET
public final static String MASTER_SECRET = "";
//推送的请求api地址
public final static String PUSH_URL = "https://bjapi.push.jiguang.cn/v3/push";
//cid 请求获取地址
public final static String CID_URL = "https://api.jpush.cn/v3/push/cid?count=1";
//需要base64 加密的数据 appKey 和masterSecret 的组合加密
public final static String AUTHORIZATION_PARM = APPKEY + ":" + MASTER_SECRET;
//True 表示推送生产环境,False 表示要推送开发环境;如果不指定则为推送生产环境。
public final static boolean APNS_PRODUCTION = false;
//保存1天 推送当前用户不在线时,为该用户保留多长时间的离线消息
public final static int TIME_TO_LIVE = 86400;
//全平台推送 ios Android
public final static String PLATFORM = "all";
}
5. 推送的基类 推送的主业务流程在这个基类里面 使用的是模版设计模式 方便子类自己去自定义通知
import com.shanhumi.appservice.core.jpush.JPush;
import com.shanhumi.appservice.core.jpush.JPushBuilder;
import com.shanhumi.appservice.core.jpush.JPushConfig;
import com.shanhumi.appservice.core.jpush.JPushData;
import org.apache.commons.collections.map.HashedMap;
import pre.cyy.request.Page;
import java.util.ArrayList;
import java.util.List;
/**
* @Author: yang
* @Date: 2018/6/13.14:54
* @Desc: AbsPush 推送基类
* 新增的推送 继承该类 实现以下三个自定义的方法
* 调用push 方法即可推送
*/
public abstract class AbsPush {
/**
* @Author yang
* @Date 2018/6/13 15:06
* @Description * @param list 推送的对象 是个list
*/
protected List registrationIds = new ArrayList<>();
/**
* @Author yang
* @Date 2018/6/14 15:47
* @Description 推送附加给app的数据
*/
protected HashedMap keyValue = new HashedMap();
/**
* @Author yang
* @Date 2018/6/13 15:06
* @Description 添加推送对象
*/
public AbsPush addRegisterId(String id) {
this.registrationIds.add(id);
return this;
}
/**
* @Author yang
* @Date 2018/6/13 15:06
* @Description 添加推送对象
*/
public AbsPush addRegisterId(List ids) {
this.registrationIds.addAll(ids);
return this;
}
/**
* @Author yang
* @Date 2018/6/14 15:51
* @Description 添加附加参数
*/
public AbsPush putKeyValue(String key, Object val) {
this.keyValue.put(key, val);
return this;
}
/**
* @Author yang
* @Date 2018/6/14 16:03
* @Description 不带自定义消息的推送
*/
public Page push() {
return push(null);
}
/**
* @param Messager 自定义消息的内容 json 数据
* @return
* @Author yang
* @Date 2018/6/13 15:02
* @Description 推送
*/
public Page push(Object Messager) {
if (registrationIds.isEmpty()) {
throw new IllegalArgumentException("至少添加一个推送者的注册id");
}
//设置发送的对象
JPushData.AudienceBean audienceBean = new JPushData.AudienceBean();
audienceBean.setRegistration_id(registrationIds);
//创建通知
JPushData.NotificationBean notificationBean = new JPushData.NotificationBean();
//自定义消息
JPushData.MessageBean messageBean = new JPushData.MessageBean();
//可选参数的设置
JPushData.OptionsBean optionsBean = new JPushData.OptionsBean();
//设置通知对象
notificationBean = customizeNotification(notificationBean, keyValue);
optionsBean = customizeOptionsBean(optionsBean);
messageBean = customizeMessager(messageBean, Messager);
JPushBuilder builder = new JPushBuilder
.build()
.setCid(JPush.getInstance().autoGenerateCid())
.setAudience(audienceBean)
.setPlatform(JPushConfig.PLATFORM) //设置发送的平台 all
.setNotification(notificationBean)
.setMessage(messageBean)
.setOptions(optionsBean)
.builder();
//数据转换 JPushData
JPushData jPushData = JPush.getInstance().convertData(builder);
//执行推送
return JPush.getInstance().push(jPushData);
}
/**
* @Author yang
* @Date 2018/6/14 17:33
* @Description 重复使用实例化对象的时候 需要调用清除方法 目的是为了不让之前的数据留下 重复推送
* 清除之前的id 和keyVal
*/
public void clear() {
this.registrationIds.clear();
this.keyValue.clear();
}
/**
* @Author yang
* @Date 2018/6/14 9:41
* @Description 自定义消息
*/
protected abstract JPushData.MessageBean customizeMessager(JPushData.MessageBean messageBean, Object messager);
/**
* @Author yang
* @Date 2018/6/13 18:55
* @Description 自定义通知模块
* 其他通知 继承该类 重写customizeNotification 方法
* 重写改模块 即可
*/
protected abstract JPushData.NotificationBean customizeNotification(JPushData.NotificationBean notificationBean, HashedMap keyValue);
/**
* @Author yang
* @Date 2018/6/13 19:15
* @Description 自定义可选参数
*/
protected abstract JPushData.OptionsBean customizeOptionsBean(JPushData.OptionsBean optionsBean);
}
6 写一个测试类 : 测试类需要继承absPush 的基类 并且重写 其中的三个自定义方法 自定义自己的通知显示和一些可选参数
import com.shanhumi.appservice.core.jpush.JPushConfig;
import com.shanhumi.appservice.core.jpush.JPushData;
import org.apache.commons.collections.map.HashedMap;
import pre.cyy.request.Page;
import java.util.ArrayList;
/**
* @Author: yang
* @Date: 2018/6/13.14:05
* @Desc: MyPush 推送测试版本
*/
public class MyPush extends AbsPush {
/**
* @Author yang
* @Date 2018/6/14 18:11
* @Description 推送时候被通知的标题
*/
private String alertMessage;
public MyPush(String alertMessage) {
this.alertMessage = alertMessage;
}
/**
* @Author yang
* @Date 2018/6/14 16:08
* @Description 自定义消息在app 为后台的情况下是收不到的 忽略不写
*/
@Override
protected JPushData.MessageBean customizeMessager(JPushData.MessageBean messageBean, Object messager) {
return null;
}
/**
* @param notificationBean 通知对象
* @param keyValue 通知附加的键值对数据
* @return
* @Author yang
* @Date 2018/6/13 16:19
* @Description 自定义的通知对象
*/
@Override
protected JPushData.NotificationBean customizeNotification(JPushData.NotificationBean notificationBean, HashedMap keyValue) {
//安卓的通知对象
JPushData.NotificationBean.AndroidBean androidBean = new JPushData.NotificationBean.AndroidBean();
//ios的通知对象
JPushData.NotificationBean.IosBean iosBean = new JPushData.NotificationBean.IosBean();
//设置安卓的通知对象
JPushData.NotificationBean.AndroidBean.ExtrasBean extrasBean = new JPushData.NotificationBean.AndroidBean.ExtrasBean();
extrasBean.setExtras(keyValue);
androidBean.setAlert(alertMessage);
androidBean.setBuilder_id(3); //Android SDK 可设置通知栏样式,这里根据样式 ID 来指定该使用哪套样式
androidBean.setTitle(alertMessage);
androidBean.setExtras(extrasBean);
notificationBean.setAndroid(androidBean);
//设置ios的通知对象
iosBean.setAlert(alertMessage);
iosBean.setBadge("+1"); //Android SDK 可设置通知栏样式,这里根据样式 ID 来指定该使用哪套样式
iosBean.setSound("sound.caf"); //设置提示的声音
//发送额外的数据
JPushData.NotificationBean.IosBean.ExtrasBeanX extrasBeanX = new JPushData.NotificationBean.IosBean.ExtrasBeanX();
extrasBeanX.setExtras(keyValue);
iosBean.setExtras(extrasBeanX);
//设置通知对象 唤起通知
notificationBean.setAndroid(androidBean);
notificationBean.setIos(iosBean);
return notificationBean;
}
/**
* @Author yang
* @Date 2018/6/13 19:14
* @Description 自定义可选参数
*/
@Override
protected JPushData.OptionsBean customizeOptionsBean(JPushData.OptionsBean optionsBean) {
optionsBean.setTime_to_live(JPushConfig.TIME_TO_LIVE);
optionsBean.setApns_production(JPushConfig.APNS_PRODUCTION);
return optionsBean;
}
/**
* @Author yang
* @Date 2018/6/13 16:21
* @Description 测试
*/
public static void main(String[] args) {
AbsPush orderPush = new MyPush("您有新的订单提醒 请注意查收");
Page page = orderPush
.addRegisterId("1114a89792fa5e9949b")
.addRegisterId("xxxxxx")
.addRegisterId(new ArrayList<>())//也可以添加一个list
.putKeyValue("order_sn", "ahskdhjkasdh2312312")//这个是推送时候附加的值 keyval的格式 支持多个
.push("我是自定义消息"); //推送自定义消息 不推送自定义消息 构造函数不添加任何数据
if (page.getStatusCode() == 200) {
System.out.println("推送成功");
} else {
System.out.println(page.getRawText());
}
}
}
测试过 很直观的调用 也容易进行扩展