一、推送在app端使用的比较多,常见的第三方推送有百度推送,极光推送,友盟推送等,其实原理都一样。以下介绍以下原理图:
1.设备绑定流程:
2.消息推送流程:
二、搞清楚了原理,下面我们来进行实战操作了
1.首先在maven工程中引入对应的maven库,如果不是maven工程,可以自行引入jar包,可以到极光官网进行下载:
cn.jpush.api
jpush-client
3.3.10
2.在用户登录接口中进行设备的绑定,我这里是示例代码(我的工程框架是springcloud),你可以酌情使用:
/**
* 用户设备和极光设备id绑定
* @param registrationId:app客户端机器的唯一识别码
* @param type:app类型 分为 ios或 android
* @return
*/
@PostMapping("app/jpushBind")
@MustLogin
public Object jpushBind(String registrationId,String type) {
if(ValidateHelper.isNullOrEmpty(registrationId)||ValidateHelper.isNullOrEmpty(type)) {
return MybData.error("registrationId、type不能为空");
}
if(!type.equals("ios")&&!type.equals("android")) {
return MybData.error("参数有误");
}
User user=getUser();//我这里是使用了注解的方式在拦截器层进行了用户的封装
jpushUtil.bind(user.getId(), new JpushInfo(registrationId, type,user.getCompanyId(),user.getId()));
return MybData.success();
}
3.jpush工具类,我这里绑定的用户和设备信息是保存在redis数据库中的,实际使用的时候你可以根据自身情况操作。另外,极光的secret和appkey需要在极光应用平台进行申请开通:
@Slf4j
@Component
public class JpushUtil {
//这里的配置可以配置在配置文件中
@Value("${jiguang.isProduct}") //是否是生产环境
private Boolean isProduct;
@Value("${jiguang.masterSecret}")
private String masterSecret;//极光应用的secret
@Value("${jiguang.appKey}")
private String appKey;//极光应用的appkey
@Autowired
private RedisUtil redis;
/**
* 设备绑定
*/
public void bind(String userId, JpushInfo jpushInfo) {
List keys = redis.scanMatch(JpushInfo.JPUSH_USER_KEY + ":" + "*");
String objStr = null;
String key = null;
Iterator iterator = keys.iterator();
JpushInfo temp = null;
// 接触当前设备以前绑定的设备信息
while (iterator.hasNext()) {
key = iterator.next();
objStr = redis.getString(key);
if (objStr != null) {
temp = JSONHelper.convertToObject(objStr, JpushInfo.class);
if (jpushInfo.getRegistrationId().equals(temp.getRegistrationId())) {
redis.remove(key);
}
}
}
log.info("======================用户设备绑定=========================");
redis.setString(JpushInfo.JPUSH_USER_KEY + ":" + userId, JSONHelper.convertToJSON(jpushInfo));
}
/**
* 解除设备绑定
*/
public void unbind( String userId) {
log.info("======================用户设备取消绑定=========================");
redis.remove(JpushInfo.JPUSH_USER_KEY + ":" + userId);
}
public void push(List list) {
try {
if (ValidateHelper.isNullOrEmpty(list)) {
return;
}
List pushPayloadList = new ArrayList();
for (JpushNotice notice : list) {
JpushInfo client = redis.getToObject(JpushInfo.JPUSH_USER_KEY + ":" + notice.getUserId(), JpushInfo.class);
if (client == null) {
continue;
}
//推送的用户信息和当前登录的用户信息不一致,不进行推送
if(notice.getCompanyId()!=null&&!notice.getCompanyId().equals(client.getCompanyId())) {
continue;
}
notice.setRegistrationId(client.getRegistrationId());
if (DeviceType.Android.value().equals(client.getClientType())) {
pushPayloadList.add(buildPushObject_android_all_alertWithTitle(notice));
} else {
pushPayloadList.add(buildPushObject_ios_all_alertWithTitle(notice));
}
}
if (ValidateHelper.isNullOrEmpty(pushPayloadList)) {
return;
}
log.info("======================开始推送消息:共" + pushPayloadList.size() + "条=========================");
JPushClient jpushClient = new JPushClient(masterSecret, appKey, null, ClientConfig.getInstance());
for (PushPayload payload : pushPayloadList) {
System.out.println(payload.toString());
PushResult result = jpushClient.sendPush(payload);
log.info(result + "................................");
log.info("Got result - " + result);
}
Thread.sleep(5000);
jpushClient.close();
} catch (Exception ex) {
log.info("==================================jpush推送异常:{}", ex);
}
}
/**
* @Title: pushPassThrough @Description: 发送穿透消息 @param: @param
* jpushNotice @return: void @throws
*/
public void pushPassThrough(JpushNotice jpushNotice) {
JpushInfo client = redis.getToObject(JpushInfo.JPUSH_USER_KEY + ":" + jpushNotice.getUserId(), JpushInfo.class);
if (client == null) {
log.info("==================================jpush推送异常:{},{}", jpushNotice.getUserId(), "JpushInfo对象不存在");
return;
}
//推送的用户信息和当前登录的用户信息不一致,不进行推送
if(jpushNotice.getCompanyId()!=null&&!jpushNotice.getCompanyId().equals(client.getCompanyId())) {
log.info("==================================推送的用户信息和当前登录的用户信息不一致,不进行推送");
return;
}
jpushNotice.setRegistrationId(client.getRegistrationId());
PushPayload pushPayload;
if (DeviceType.Android.value().equals(client.getClientType())) {
pushPayload = buildPushObject_android_passThrough_alertWithTitle(jpushNotice);
} else {
pushPayload = buildPushObject_ios_passThrough_alertWithTitle(jpushNotice);
}
JPushClient jpushClient = new JPushClient(masterSecret, appKey, null, ClientConfig.getInstance());
log.info("推送消息:{}", pushPayload.toString());
PushResult result = null;
try {
result = jpushClient.sendPush(pushPayload);
log.info(result + "................................");
log.info("Got result - " + result);
Thread.sleep(5000);
jpushClient.close();
} catch (Exception e) {
log.error("==================================jpush推送异常:{}", e);
}
}
/**
* 透传消息android
*/
private PushPayload buildPushObject_android_passThrough_alertWithTitle(JpushNotice notice) {
return PushPayload.newBuilder()
// 指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台
.setPlatform(Platform.android())
// 指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
.setAudience(Audience.registrationId(notice.getRegistrationId()))
// Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息,
// sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
// [通知与自定义消息有什么区别?]了解通知和自定义消息的区别
.setMessage(Message.newBuilder().setContentType(notice.getContentType()).setMsgContent(notice.getMsgContent()).setTitle(notice.getMsgTitle()).addExtras(notice.getExtrasparamMap()).build()).setOptions(Options.newBuilder()
// 此字段是给开发者自己给推送编号,方便推送者分辨推送记录
.setSendno(1)
// 此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天,单位为秒
// .setTimeToLive(jpushModel.getTimeToLive())
// 此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义
.setApnsProduction(isProduct).build())
.build();
}
/**
* 透传消息ios
*/
private PushPayload buildPushObject_ios_passThrough_alertWithTitle(JpushNotice notice) {
return PushPayload.newBuilder()
// 指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台
.setPlatform(Platform.ios())
// 指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
.setAudience(Audience.registrationId(notice.getRegistrationId()))
// Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息,
// sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
// [通知与自定义消息有什么区别?]了解通知和自定义消息的区别
.setMessage(Message.newBuilder().setContentType(notice.getContentType()).setMsgContent(notice.getMsgContent()).setTitle(notice.getMsgTitle()).addExtras(notice.getExtrasparamMap()).build()).setOptions(Options.newBuilder()
// 此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义
.setApnsProduction(isProduct)
// 此字段是给开发者自己给推送编号,方便推送者分辨推送记录
.setSendno(1)
// 此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天,单位为秒
// .setTimeToLive(jpushModel.getTimeToLive())
.build())
.build();
}
/**
* 构建安卓推送环境
*/
private PushPayload buildPushObject_android_all_alertWithTitle(JpushNotice notice) {
return PushPayload.newBuilder()
// 指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台
.setPlatform(Platform.android())
// 指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
.setAudience(Audience.registrationId(notice.getRegistrationId()))
// jpush的通知,android的由jpush直接下发,iOS的由apns服务器下发,Winphone的由mpns下发
.setNotification(Notification.newBuilder()
// 指定当前推送的android通知
.addPlatformNotification(AndroidNotification.newBuilder().setAlert(notice.getMsgContent()).setTitle(notice.getMsgTitle())
// 此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value)
.addExtras(notice.getExtrasparamMap()).build())
.build())
// Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息,
// sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
// [通知与自定义消息有什么区别?]了解通知和自定义消息的区别
.setMessage(Message.newBuilder().setContentType(notice.getContentType()).setMsgContent(notice.getMsgContent()).setTitle(notice.getMsgTitle()).addExtras(notice.getExtrasparamMap()).build()).setOptions(Options.newBuilder()
// 此字段是给开发者自己给推送编号,方便推送者分辨推送记录
.setSendno(1)
// 此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天,单位为秒
// .setTimeToLive(jpushModel.getTimeToLive())
// 此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义
.setApnsProduction(isProduct).build())
.build();
}
/**
* 构建ios推送环境
*
* @Title: buildPushObject_ios_all_alertWithTitle
*/
private PushPayload buildPushObject_ios_all_alertWithTitle(JpushNotice notice) {
IosNotification.Builder builder = IosNotification.newBuilder()
// 传一个IosAlert对象,指定apns title、title、subtitle等
.setAlert(IosAlert.newBuilder().setTitleAndBody(notice.getMsgTitle(), null, notice.getMsgContent()).build())
// 直接传alert
// 此字段的值default表示系统默认声音;传sound.caf表示此推送以项目里面打包的sound.caf声音来提醒,
// 如果系统没有此音频则以系统默认声音提醒;此字段如果传空字符串,iOS9及以上的系统是无声音提醒,以下的系统是默认声音
// .setSound(jpushModel.getSound())
// 此字段为透传字段,不会显示在通知栏。用户可以通过此字段来做一些定制需求,如特定的key传要指定跳转的页面(value)
.addExtras(notice.getExtrasparamMap());
// 此项说明此推送是一个background推送,想了解background看:http://docs.jpush.io/client/ios_tutorials/#ios-7-background-remote-notification
// .setContentAvailable(true)
if (!JpushNotice.PASSTHROUGH.equals(notice.getContentType())) {
// 此项是指定此推送的badge自动加1
builder = builder.incrBadge(1);
}
return PushPayload.newBuilder()
// 指定要推送的平台,all代表当前应用配置了的所有平台,也可以传android等具体平台
.setPlatform(Platform.ios())
// 指定推送的接收对象,all代表所有人,也可以指定已经设置成功的tag或alias或该应应用客户端调用接口获取到的registration id
.setAudience(Audience.registrationId(notice.getRegistrationId()))
// jpush的通知,android的由jpush直接下发,iOS的由apns服务器下发,Winphone的由mpns下发
.setNotification(Notification.newBuilder()
// 指定当前推送的android通知
.addPlatformNotification(builder.build()).build())
// Platform指定了哪些平台就会像指定平台中符合推送条件的设备进行推送。 jpush的自定义消息,
// sdk默认不做任何处理,不会有通知提示。建议看文档http://docs.jpush.io/guideline/faq/的
// [通知与自定义消息有什么区别?]了解通知和自定义消息的区别
.setMessage(Message.newBuilder().setContentType(notice.getContentType()).setMsgContent(notice.getMsgContent()).setTitle(notice.getMsgTitle()).addExtras(notice.getExtrasparamMap()).build()).setOptions(Options.newBuilder()
// 此字段的值是用来指定本推送要推送的apns环境,false表示开发,true表示生产;对android和自定义消息无意义
.setApnsProduction(isProduct)
// 此字段是给开发者自己给推送编号,方便推送者分辨推送记录
.setSendno(1)
// 此字段的值是用来指定本推送的离线保存时长,如果不传此字段则默认保存一天,最多指定保留十天,单位为秒
// .setTimeToLive(jpushModel.getTimeToLive())
.build())
.build();
}
}
4.生产消息并开始推到极光的服务器:
//组装开始推送(多条进行推送)
private void sendJpushNotice(List noticeList) {
if (ValidateHelper.isNullOrEmpty(noticeList)) {
return;
}
List list = new ArrayList<>();
for (Notice n : noticeList) {
JpushNotice jn = new JpushNotice();
Map map = new HashMap<>();
map.put("orderId", n.getOrderId());
map.put("goodsId", n.getGoodsId());
map.put("type", n.getType().toString());
map.put("id", n.getId() == null ? null : n.getId().toString());
map.put("title", n.getTitle());
map.put("summary", n.getSummary());
map.put("showContent", n.getShowContent());
map.put("createTime", TimeHelper.formatDate(new Date(), "yyyy-MM月dd日 HH:mm:ss"));
map.put("status", n.getStatus().toString());
jn.setExtrasparamMap(map);
jn.setMsgContent(TextHelper.replaceHTML(n.getShowContent()));
jn.setMsgTitle(n.getTitle());
jn.setCompanyId(n.getCompanyId());
jn.setUserId(n.getReceiverUserId());
list.add(jn);
}
// 开始推送
jpushUtil.push(list);}
总结,好了,以上就是极光推送的全部流程和部分代码,大家只要明白其中的原理,一般都能做出推送的,还有不清楚的地方请给我留言!