之前写了一篇 websocket 的:web管理后台与微信公众号的消息会话,那么今天我们来聊聊另外一个长连接的技术–极光推送,已经项目实战,直接复制即可使用。
1、在平时开发中,可能需要服务端对客户端实时的推送一些消息,例如在世界杯期间,一些球星的新闻以及最新的赛场状态,都是需要很快并且精准的推送到用户的手机
2、我们平时做的一般都是由客户端调取服务端的接口来进行一些数据交互,然而服务端却无法主动像客户端发送数据,这个时候推送就应运而生了
1、在 pom 引入对应的极光包以及依赖包,这里直接拿官网的 pom 文件:
官网 java sdk 地址
cn.jpush.api
jiguang-common
1.1.4
io.netty
netty-all
4.1.6.Final
compile
com.google.code.gson
gson
2.3
org.slf4j
slf4j-api
1.7.7
org.slf4j
slf4j-log4j12
1.7.7
log4j
log4j
1.2.17
引入依赖以后,如果调用极光的 api 报错,可以重新打包到 maven 仓库一次
1、极光推送有三种推送目标:别名(alias)、tag(标签)、RegistrationID
本流程图只介绍 RegisterationID 的目标推送,别名以及标签目标的方式由业务后台服务端和 app 端来共同协商用什么来做标签或者别名,
2、代码
JiGuangPushUtil
package com.tanxi.faith.util;
import cn.jiguang.common.ClientConfig;
import cn.jiguang.common.ServiceHelper;
import cn.jiguang.common.connection.NettyHttpClient;
import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jiguang.common.resp.ResponseWrapper;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Message;
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.audience.AudienceTarget;
import cn.jpush.api.push.model.notification.AndroidNotification;
import com.gizwits.boot.utils.ParamUtil;
import com.gizwits.boot.utils.SysConfigUtils;
import com.gizwits.lease.config.CommonSystemConfig;
import io.netty.handler.codec.http.HttpMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.jpush.api.push.model.notification.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Iterator;
import java.util.Map;
/**
* Description:极光推送api
* User: tanxi
* Date: 2019-02-22
*/
public class JiGuangUtil {
public static void main(String[] args){
// testSendPush("推送消息","");
}
protected static final Logger LOG = LoggerFactory.getLogger("");
// demo App defined in resources/jpush-api.conf
protected static final String APP_KEY ="XXXXX";
protected static final String MASTER_SECRET = "XXXXX";
protected static final String GROUP_PUSH_KEY = "XXXXXX";
protected static final String GROUP_MASTER_SECRET = "XXXXXX";
public static final String TITLE = "Test from API example";
public static final String ALERT = "Test from API Example - alert";
public static final String MSG_CONTENT = "Test from API Example - msgContent";
public static final String REGISTRATION_ID = "XXXXX";
public static final String TAG = "tag_api";
public static long sendCount = 0;
private static long sendTotalTime = 0;
private static void sendToJiGuang(String message,String mobile,Map map){
buildPushObject_ios_audienceMore_messageWithExtras(message,mobile,map);
testSendPushWithCallback(message,mobile);
}
public static PushPayload buildPushObject_all_alias_alert(String message,String mobile) {
return PushPayload.newBuilder()
.setPlatform(Platform.all())
.setAudience(Audience.alias("alias1"))
.setNotification(Notification.alert(ALERT))
.build();
}
// 使用 NettyHttpClient 异步接口发送请求
public static void testSendPushWithCallback(String message,String mobile) {
CommonSystemConfig commonSystemConfig = SysConfigUtils.get(CommonSystemConfig.class);
String appkey = commonSystemConfig.getJiGuangAppKey();
String appSecret = commonSystemConfig.getjiGuangAppSecret();
ClientConfig clientConfig = ClientConfig.getInstance();
String host = (String) clientConfig.get(ClientConfig.PUSH_HOST_NAME);
final NettyHttpClient client = new NettyHttpClient(ServiceHelper.getBasicAuthorization(appkey, appSecret),
null, clientConfig);
try {
URI uri = new URI(host + clientConfig.get(ClientConfig.PUSH_PATH));
PushPayload payload = buildPushObject_all_alias_alert(message,mobile);
client.sendRequest(HttpMethod.POST, payload.toString(), uri, new NettyHttpClient.BaseCallback() {
@Override
public void onSucceed(ResponseWrapper responseWrapper) {
LOG.info("Got result: " + responseWrapper.responseContent);
}
});
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
/**
*构建推送对象:平台是 Andorid 与 iOS,推送目标是 ("tag1" 与 "tag2" 的并集)
* 交("alias1" 与 "alias2" 的并集),推送内容是 - 内容为 MSG_CONTENT 的消息,
* 并且附加字段 from = JPush。
* @param message
* @return
*/
public static PushPayload buildPushObject_ios_audienceMore_messageWithExtras(String message,String mobile,Map map) {
Message.Builder builder = Message.newBuilder();
//设置消息内容
builder.setMsgContent(message);
//设置附件字段,可以自定义设置
Iterator iterator = map.keySet().iterator();
while(iterator.hasNext()){
String key = iterator.next();
builder.addExtra(key,map.get(key));
}
if (!ParamUtil.isNullOrEmptyOrZero(mobile)){
/**
* 推送的关键就是构建一个 payload 的对象,如下是构建一个推送平台是安卓、ios平台,推送目标是设置手
* 机号为别名的自定义消息
*
*/
return PushPayload.newBuilder()
.setPlatform(Platform.android_ios())
.setAudience(Audience.newBuilder()
/**
* 这里如改为 AudienceTarget.registrationId(String registerationID),即推送给 app 端 对应
* RegisterationID 的用户设备,可以点对点推送给某一个,也可以批量推送给用户
*/
.addAudienceTarget(AudienceTarget.alias(mobile))
.build())
.setMessage(builder
.build())
.build();
}
// 假如手机号为空,推送给别名为 alias1 的目标
return PushPayload.newBuilder()
.setPlatform(Platform.android_ios())
.setAudience(Audience.newBuilder()
.addAudienceTarget(AudienceTarget.alias("alias1"))
.build())
.setMessage(builder
.build())
.build();
}
public static void testSendPush(String appKey,String appSecret,String message,String mobile,Map map) {
ClientConfig clientConfig = ClientConfig.getInstance();
final JPushClient jpushClient = new JPushClient(appSecret, appKey, null, clientConfig);
// Here you can use NativeHttpClient or NettyHttpClient or ApacheHttpClient.
// Call setHttpClient to set httpClient,
// If you don't invoke this method, default httpClient will use NativeHttpClient.
// ApacheHttpClient httpClient = new ApacheHttpClient(authCode, null, clientConfig);
// jpushClient.getPushClient().setHttpClient(httpClient);
final PushPayload payload = buildPushObject_ios_audienceMore_messageWithExtras(message,mobile,map);
// // For push, all you need do is to build PushPayload object.
// PushPayload payload = buildPushObject_all_alias_alert();
try {
PushResult result = jpushClient.sendPush(payload);
LOG.info("Got result - " + result);
/**
* 如果使用 NettyHttpClient(v3.2.15 版本新增),需要在响应返回后手动调用一下 NettyHttpClient 中的 close
* 方法,否则进程不会退出
*/
// jpushClient.close();
} catch (APIConnectionException e) {
LOG.error("Connection error. Should retry later. ", e);
LOG.error("Sendno: " + payload.getSendno());
} catch (APIRequestException e) {
LOG.error("Error response from JPush server. Should review and fix it. ", e);
LOG.info("HTTP Status: " + e.getStatus());
LOG.info("Error Code: " + e.getErrorCode());
LOG.info("Error Message: " + e.getErrorMessage());
LOG.info("Msg ID: " + e.getMsgId());
LOG.error("Sendno: " + payload.getSendno());
}
}
}
ParameterUtil
public static boolean isNullOrEmptyOrZero(Object obj) {
if (obj == null) {
return true;
}
if (obj instanceof Long) {
Long value = (Long) obj;
return value <= 0;
} else if (obj instanceof Integer) {
Integer value = (Integer) obj;
return value <= 0;
} else if (obj instanceof Double) {
Double value = (Double) obj;
return value <= 0;
} else if (obj instanceof String) {
String value = (String) obj;
return StringUtils.isEmpty(value) || StringUtils.isBlank(value);
} else if (obj instanceof List) {
List value = (List) obj;
return value.size() <= 0;
}
return false;
}
当需要调用api的时候,在代码里直接通过如下调用方式实现极光推送
JiGuangUtil.testSendPush(appkey,appSecret ,消息内容,手机号也就是我这里的推送目标,自定义即可用来做附加字段)
常见问题指南见官网
四、总结
极光推送的实现并不复杂,只需要将极光推送的工作原理理解透彻,理解不同推送对象、不同推送目标的区别,在极光的后台我们去查看极光的推送历史。这里提一点,如果极光服务器所在地为北京的应用,调用方服务器也位于北京的话,使用 bjapi.jiguang.cn 作为调用地址,可以提升 api 响应速度。
以上就是本人总结的极光推送实战,如有错误或者交流,欢迎留言评论联系