因为工作需要,甲方单位使用极光推送总是出现用户收取不到推送消息,甲方要求我们使用个推。
因为我们访问网络的时候使用的是代理,所以个推提供的接口发送接口不能使用,所以需要重新写一个支持代理的http链接。目前项目中的个推使用流程如下:
目前使用的是群推:pushToList,群推第一步使用taskid ,taskid 就是我们的消息在推送平台对应的一个映射id,通过taskid 来找这个消息。第二部是发送消息。发送消息的流程和获取taskId的流程几乎是一致的,就是在发送的过程中,gt_action 传的参数不一样,获取taskid 时传的是getContentIdAction,而推送消息的时候使用的是pushMessageToListAction。
个推的推送过程是:
http 代理代码如下:
package com.ruim.ifsp.merser.util;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.ruim.ifsp.log.IfspLoggerFactory;
import com.ruim.ifsp.merser.cache.CommonConstants;
import com.ruim.ifsp.utils.client.http.IfspHttpClientUtil;
import org.slf4j.Logger;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.URL;
/**
* 个推
* @author lxw
* @deprecated 个推消息推送http链接
*/
public class IGtpushHttpClient extends IfspHttpClientUtil {
private static Logger logger = IfspLoggerFactory.getLogger(JpushHttpClient.class);
static String proxyIp = CommonConstants.getProperties("PROXY_IP");
static String proxyProt = CommonConstants.getProperties("PROXY_PORT");
// private static String appId = "TxzlIyCcfS9KuENjjP4ux1";
// private static String appKey = "rAnoicfrNX7915IxPocAL2";
// private static String masterSecret = "KFDNBNKAVj9bgykwvqgeA5";
// static String host = "http://sdk.open.api.igexin.com/apiex.htm";
private static String appId = CommonConstants.getProperties("IGTAPP_ID");//个推appid
private static String appKey = CommonConstants.getProperties("IGTAPP_KEY");//应用appKey
private static String masterSecret = CommonConstants.getProperties("IGTMASTER_SECRET");//应用证书号
private static String host = CommonConstants.getProperties("IGTPUST_HOST");//个推送地址
public static HttpURLConnection buildConnect(String Action) throws Exception {
URL url = new URL(host);
logger.info("开始初始化服务器连接...");
logger.info("服务器地址:[ " + url + " ]");
/**启用代理*/
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyIp, Integer.valueOf(proxyProt)));
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection(proxy);
httpURLConnection.setConnectTimeout(30000);
httpURLConnection.setReadTimeout(30000);
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);
httpURLConnection.setUseCaches(false);
httpURLConnection.setRequestProperty("Content-Type", "text/html;charset=UTF-8");
httpURLConnection.setRequestProperty("Gt-Action", Action);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.connect();
logger.info("服务器连接完成...");
return httpURLConnection;
}
public static void sendMsg(HttpURLConnection httpURLConnection,String message) throws Exception {
logger.info("上送服务报文开始...");
logger.info("上送报文:[" + message + "]");
OutputStream outputStream = null;
try {
outputStream = httpURLConnection.getOutputStream();
// 注意编码格式,防止中文乱码
if (StringUtils.isNotEmpty(message)) {
outputStream.write(message.getBytes("utf-8"));
} else {
outputStream.write("".getBytes());
}
if (null != outputStream)
outputStream.close();
logger.info("上送服务报文完成...");
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
if (null != outputStream)
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static String receiveMsg(HttpURLConnection httpURLConnection) throws IOException {
logger.debug("接收服务器响应报文开始...");
InputStream in = null;
StringBuilder sb = new StringBuilder(1024);
BufferedReader br = null;
String temp = null;
int code = httpURLConnection.getResponseCode();
if (200 == code) {
in = httpURLConnection.getInputStream();
br = new BufferedReader(new InputStreamReader(in, "utf-8"));
while (null != (temp = br.readLine())) {
sb.append(temp);
}
} else {
in = httpURLConnection.getErrorStream();
br = new BufferedReader(new InputStreamReader(in, "utf-8"));
while (null != (temp = br.readLine())) {
sb.append(temp);
}
}
String str1 = sb.toString();
logger.info("报文: [ " + str1 + " ] ");
logger.info("接收服务器响应报文完成");
return str1;
}
}
推送消息代码:
package com.ruim.ifsp.merser.util;
import com.gexin.rp.sdk.base.IPushResult;
import com.gexin.rp.sdk.base.impl.*;
import com.gexin.rp.sdk.base.payload.APNPayload;
import com.gexin.rp.sdk.base.payload.Payload;
import com.gexin.rp.sdk.base.uitls.Base64Util;
import com.gexin.rp.sdk.base.uitls.LangUtil;
import com.gexin.rp.sdk.base.uitls.SignUtil;
import com.gexin.rp.sdk.http.IGtPush;
import com.gexin.rp.sdk.http.utils.GTConfig;
import com.gexin.rp.sdk.http.utils.ParamUtils;
import com.gexin.rp.sdk.template.LinkTemplate;
import com.gexin.rp.sdk.template.NotificationTemplate;
import com.ruim.ifsp.exception.BizException;
import com.ruim.ifsp.log.IfspLoggerFactory;
import com.ruim.ifsp.merser.cache.CommonConstants;
import com.ruim.ifsp.utils.message.IfspFastJsonUtil;
import com.ruim.ifsp.utils.verify.IfspDataVerifyUtil;
import org.slf4j.Logger;
import java.net.HttpURLConnection;
import java.time.format.TextStyle;
import java.util.*;
public class IGtpushThread extends Thread {
private static Logger log = IfspLoggerFactory.getLogger(IGtpushThread.class);
private static String appId = CommonConstants.getProperties("IGTAPP_ID");;
private static String appKey = CommonConstants.getProperties("IGTAPP_KEY");
private static String masterSecret = CommonConstants.getProperties("IGTMASTER_SECRET");
private static String host = CommonConstants.getProperties("IGTPUST_HOST");
private String alias;
private String message;
private String msgSendType;
public IGtpushThread(String alias,String message,String msgSendType) {
// super();
this.alias = alias;
this.message = message;
this.msgSendType = msgSendType;
}
/**
* If this thread was constructed using a separate
* Runnable
run object, then that
* Runnable
object's run
method is called;
* otherwise, this method does nothing and returns.
*
* Subclasses of Thread
should override this method.
*
* @see #start()
* @see #stop()
* @see #(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
IGTpushMsg(alias,message,msgSendType);
}
public void IGTpushMsg(String alias,String message,String msgSendType){
String respMsg = new String();
String[] arr = alias.split(",");
// 通知透传模板 消息传递
NotificationTemplate template = notificationTemplateDemo(message);
ListMessage messages = new ListMessage();
messages.setData(template);
// 设置消息离线,并设置离线时间
messages.setOffline(true);
// 离线有效时间,单位为毫秒,可选
messages.setOfflineExpireTime(24 * 1000 * 3600);
// 配置推送目标
List targets = new ArrayList();
// taskId用于在推送时去查找对应的message
try{
String taskId = getListAppContentId(messages,null);
Map postData = null;
for (int i = 0; i < arr.length; i++) {
Target target = new Target();
target.setAppId(appId);
target.setAlias(arr[i]);
targets.add(target);
//每50个别名(CID)推送一次
if (arr.length>50&&targets.size()==50){
postData =pushMessageToList(taskId,targets);
Map response = httpResponse(postData);
if (!"ok".equals(response.get("result"))){
response = httpResponse(postData);
respMsg = IfspFastJsonUtil.mapTOjson(response);
log.info("个推建议值推送结果是:"+respMsg);
}
targets.clear();
}
}
if (targets.size()>0){
postData =pushMessageToList(taskId,targets);
Map response = httpResponse(postData);
if (!"ok".equals(response.get("result"))){
response = httpResponse(postData);
respMsg = IfspFastJsonUtil.mapTOjson(response);
log.info("个推第二次推送结果是:"+respMsg);
}
}
}catch (Exception e){
log.error("个推推送失败,原因是:"+e.getMessage());
}
}
public Map pushMessageToList(String contentId, List targetList) throws Exception{
Map postData = new HashMap();
postData.put("authToken", null);
postData.put("action", "pushMessageToListAction");
postData.put("appkey", appKey);
postData.put("contentId", contentId);
boolean needDetails = GTConfig.isPushListNeedDetails();
postData.put("needDetails", needDetails);
boolean async = GTConfig.isPushListAsync();
postData.put("async", async);
boolean needAliasDetails = GTConfig.isPushListNeedAliasDetails();
postData.put("needAliasDetails", needAliasDetails);
int limit;
if (async && !needDetails) {
limit = GTConfig.getAsyncListLimit();
} else {
limit = GTConfig.getSyncListLimit();
}
if (targetList.size() > limit) {
throw new BizException("1000","target size:" + targetList.size() + " beyond the limit:" + limit);
} else {
List clientIdList = new ArrayList();
List aliasList = new ArrayList();
String appId = null;
Iterator var12 = targetList.iterator();
while(true) {
Target target;
do {
if (!var12.hasNext()) {
postData.put("appId", appId);
postData.put("clientIdList", clientIdList);
postData.put("aliasList", aliasList);
postData.put("type", 2);
return postData;
}
target = (Target)var12.next();
String targetCid = target.getClientId();
String targetAlias = target.getAlias();
if (targetCid != null && !"".equals(targetCid.trim())) {
clientIdList.add(targetCid);
} else if (targetAlias != null && !"".equals(targetAlias.trim())) {
aliasList.add(targetAlias);
}
} while(appId != null && !"".equals(appId.trim()));
appId = target.getAppId();
}
}
//苹果参数组装
}
public NotificationTemplate notificationTemplateDemo(String message) {
NotificationTemplate template = new NotificationTemplate();
// 设置APPID与APPKEY
template.setAppId(appId);
template.setAppkey(appKey);
// 设置通知栏标题与内容
template.setTitle("");
template.setText("");
// // 配置通知栏图标
// template.setLogo("icon.png");
// 配置通知栏网络图标
// template.setLogoUrl("");
// 设置通知是否响铃,震动,或者可清除
// template.setIsRing(true);
// template.setIsVibrate(true);
// template.setIsClearable(true);
// 透传消息设置,1为强制启动应用,客户端接收到消息后就会立即启动应用;2为等待应用启动
template.setTransmissionType(2);
template.setTransmissionContent(message);
//ios 消息推送
// APNPayload apnPayload = new APNPayload();
// APNPayload.SimpleAlertMsg alertMsg = new APNPayload.SimpleAlertMsg(message);
// apnPayload.setAlertMsg(alertMsg);
// template.setAPNInfo(apnPayload);
return template;
}
public static void main(String[] args) throws Exception {
//单推测试
// LinkTemplate template = linkTemplateDemo();
// SingleMessage message = new SingleMessage();
// message.setOffline(true);
// // 离线有效时间,单位为毫秒,可选
// message.setOfflineExpireTime(24 * 3600 * 1000);
// message.setData(template);
// // 可选,1为wifi,0为不限制网络环境。根据手机处于的网络情况,决定是否下发
// message.setPushNetWorkType(0);
// Target target = new Target();
// target.setAppId(appId);
// target.setAlias("201006700000010_18611111116");
// IPushResult ret = null;
// Map reqMap = getSingleMessagePostData(message,target,null);
// String requestMsg = IfspFastJsonUtil.mapTOjson(reqMap);
// long startTime=System.currentTimeMillis();
//// HttpURLConnection client = null;
// try {
// HttpURLConnection client = null;
// client = IGtpushHttpClient.buildConnect(reqMap.get("action").toString());
// IGtpushHttpClient.sendMsg(client, requestMsg);
// String respMsg =IGtpushHttpClient.receiveMsg(client);
// client.disconnect();
// Map responseDate = (Map) IfspFastJsonUtil.jsonTOmap(respMsg);
// if ("sign_error".equals(responseDate.get("result"))){
// Map post = new HashMap<>();
// long timeStamp = System.currentTimeMillis();
// String sign = SignUtil.getSign(appKey, masterSecret, timeStamp);
// post.put("action", "connect");
// post.put("appkey", appKey);
// post.put("timeStamp", timeStamp);
// post.put("sign", sign);
// post.put("version", GTConfig.getSDKVersion());
// client = IGtpushHttpClient.buildConnect(post.get("action").toString());
// IGtpushHttpClient.sendMsg(client, IfspFastJsonUtil.mapTOjson(post).toString());
// String resp = IGtpushHttpClient.receiveMsg(client);
// Map respDate = (Map) IfspFastJsonUtil.jsonTOmap(resp);
// reqMap.put("authToken",respDate.get("authtoken"));
// client.disconnect();
// }
// client = IGtpushHttpClient.buildConnect(reqMap.get("action").toString());
//// client.setRequestProperty("Gt-Action",reqMap.get("action").toString());
// String reqMsg = IfspFastJsonUtil.mapTOjson(reqMap);
// IGtpushHttpClient.sendMsg(client, reqMsg);
// String respMseeage =IGtpushHttpClient.receiveMsg(client);
//
// } catch (Exception e) {
//
//// try {
//// client = IGtpushHttpClient.buildConnect();
//// IGtpushHttpClient.sendMsg(client, requestMsg);
//// IGtpushHttpClient.receiveMsg(client);
//// } catch (Exception e1) {
// e.printStackTrace();
//// }
// }finally {
//// if(client != null){
//// client.disconnect();
//// }
// }
// long endTime=System.currentTimeMillis();
// }
// 群推测试
// 通知透传模板
// NotificationTemplate template = notificationTemplateDemo();
// ListMessage message = new ListMessage();
// message.setData(template);
// // 设置消息离线,并设置离线时间
// message.setOffline(true);
// // 离线有效时间,单位为毫秒,可选
// message.setOfflineExpireTime(24 * 1000 * 3600);
// // 配置推送目标
// List targets = new ArrayList();
// Target target1 = new Target();
// Target target2 = new Target();
// target1.setAppId(appId);
// target1.setAlias("201006700000010_18611111116");
// targets.add(target1);
// // taskId用于在推送时去查找对应的message
// String taskId = getListAppContentId(message,null);
// Map ret = pushMessageToList(taskId, targets);
//// String requestMsg = IfspFastJsonUtil.mapTOjson(ret);
// long startTime=System.currentTimeMillis();
// HttpURLConnection client = null;
// try {
// ret.put("version", GTConfig.getSDKVersion());
// ret.put("authToken",null);
// String requestMsg = IfspFastJsonUtil.mapTOjson(ret);
// client = IGtpushHttpClient.buildConnect(ret.get("action").toString());
// IGtpushHttpClient.sendMsg(client, requestMsg);
// String response = IGtpushHttpClient.receiveMsg(client);
// client.disconnect();
// Map responseDate = (Map) IfspFastJsonUtil.jsonTOmap(response);
// if ("sign_error".equals(responseDate.get("result"))){
// Map post = new HashMap<>();
// long timeStamp = System.currentTimeMillis();
// String sign = SignUtil.getSign(appKey, masterSecret, timeStamp);
// post.put("action", "connect");
// post.put("appkey", appKey);
// post.put("timeStamp", timeStamp);
// post.put("sign", sign);
// post.put("version", GTConfig.getSDKVersion());
// client = IGtpushHttpClient.buildConnect(post.get("action").toString());
// IGtpushHttpClient.sendMsg(client, IfspFastJsonUtil.mapTOjson(post).toString());
// String resp = IGtpushHttpClient.receiveMsg(client);
// Map respDate = (Map) IfspFastJsonUtil.jsonTOmap(resp);
// ret.put("authToken",respDate.get("authtoken"));
// client.disconnect();
// }
// client = IGtpushHttpClient.buildConnect(ret.get("action").toString());
// String reqMsg = IfspFastJsonUtil.mapTOjson(ret);
// IGtpushHttpClient.sendMsg(client, reqMsg);
// String respMseeage =IGtpushHttpClient.receiveMsg(client);
// System.out.println(respMseeage);
// } catch (Exception e) {
// e.printStackTrace();
// }finally {
// if(client != null){
// client.disconnect();
// }
// }
}
private String getListAppContentId(Message message, String taskGroupName) {
Map postData = new HashMap();
Map response = null;
if (taskGroupName != null) {
postData.put("taskGroupName", taskGroupName);
}
postData.put("action", "getContentIdAction");
postData.put("appkey", appKey);
postData.put("clientData", Base64Util.getBASE64(message.getData().getTransparent().toByteArray()));
postData.put("transmissionContent", message.getData().getTransmissionContent());
postData.put("isOffline", message.isOffline());
postData.put("offlineExpireTime", message.getOfflineExpireTime());
postData.put("pushType", message.getData().getPushType());
postData.put("type", 2);
if (message instanceof ListMessage) {
postData.put("contentType", 1);
} else if (message instanceof AppMessage) {
postData.put("contentType", 2);
AppMessage appMessage = (AppMessage) message;
ParamUtils.checkAppid(message, appMessage.getAppIdList());
postData.put("appIdList", appMessage.getAppIdList());
List phoneTypeList = null;
List provinceList = null;
List tagList = null;
new ArrayList();
if (appMessage.getConditions() == null) {
phoneTypeList = appMessage.getPhoneTypeList();
provinceList = appMessage.getProvinceList();
tagList = appMessage.getTagList();
postData.put("phoneTypeList", phoneTypeList);
postData.put("provinceList", provinceList);
postData.put("tagList", tagList);
} else {
List
运行时需要引入个推的jar包,maven 引入时需要先将jar包上传到服务器中,然后在maven配置文件中。我是用的版本jra包是:
至于详细的文档可以参考官方提供的文档,地址:http://docs.getui.com/getui/server/java/start/
使用个推的时候如果不使用代理的话可以直接使用下载的文件中test工程中的代码,集成jra包后,可以参考单推,群推,直接使用。如果使用代理的话就需要重新写http链接。
个推的单推接口调用没有频次的限制,群推pushToList 接口调用是有频次限制的,就是每天调用200万次,每次发给用户数量建议50,pushToapp 每天不超过100次,每分钟不能超过5次。
使用官方提供的接口时:
每次初始化IGtPush这个类的时候都会去个推平台查询那些可用的推送地址。
然后推送消息的时候,步骤就如我画的流程图一样了,只不过单推pushTosigle 时没有获取TaskId这一步。
---------------二更---------------------------
由于我是使用的服务端,不区分安卓和ios所以使用的消息模板NotificationTemplate(通知)不能够满足要求(这个模板如果添加了iOS带码的话,就不能推送安卓了)所以要将消息模板换成TransmissionTemplate(透传)这个模板,然后在模板中设置三方通知。具体的代码如下:
package com.ruim.ifsp.merser.util;
import com.gexin.rp.sdk.base.impl.*;
import com.gexin.rp.sdk.base.notify.Notify;
import com.gexin.rp.sdk.base.payload.APNPayload;
import com.gexin.rp.sdk.base.uitls.Base64Util;
import com.gexin.rp.sdk.base.uitls.LangUtil;
import com.gexin.rp.sdk.base.uitls.SignUtil;
import com.gexin.rp.sdk.dto.GtReq;
import com.gexin.rp.sdk.http.utils.GTConfig;
import com.gexin.rp.sdk.http.utils.ParamUtils;
import com.gexin.rp.sdk.template.TransmissionTemplate;
import com.ruim.ifsp.exception.BizException;
import com.ruim.ifsp.log.IfspLoggerFactory;
import com.ruim.ifsp.merser.cache.CommonConstants;
import com.ruim.ifsp.utils.message.IfspFastJsonUtil;
import org.slf4j.Logger;
import java.net.HttpURLConnection;
import java.util.*;
public class IGtpushThread extends Thread {
private static Logger log = IfspLoggerFactory.getLogger(IGtpushThread.class);
private static String appId = CommonConstants.getProperties("IGTAPP_ID");
private static String appKey = CommonConstants.getProperties("IGTAPP_KEY");
private static String masterSecret = CommonConstants.getProperties("IGTMASTER_SECRET");
private static String host = CommonConstants.getProperties("IGTPUST_HOST");
private String alias;
private String message;
private String msgSendType;
public IGtpushThread(String alias,String message,String msgSendType) {
this.alias = alias;
this.message = message;
this.msgSendType = msgSendType;
}
/**
* If this thread was constructed using a separate
* Runnable
run object, then that
* Runnable
object's run
method is called;
* otherwise, this method does nothing and returns.
*
* Subclasses of Thread
should override this method.
*
* @see #start()
* @see #stop()
* @see #(ThreadGroup, Runnable, String)
*/
@Override
public void run() {
IGTpushMsg(alias,message,msgSendType);
}
public void IGTpushMsg(String alias,String message,String msgSendType){
String respMsg = new String();
String[] arr = alias.split(",");
// 通知透传模板 消息传递
TransmissionTemplate template = notificationTemplateDemo(message);
ListMessage messages = new ListMessage();
messages.setData(template);
// 设置消息离线,并设置离线时间
messages.setOffline(true);
// 离线有效时间,单位为毫秒,可选
messages.setOfflineExpireTime(24 * 1000 * 3600);
// 配置推送目标
List targets = new ArrayList();
// taskId用于在推送时去查找对应的message
try{
String taskId = getListAppContentId(messages,null);
Map postData = null;
for (int i = 0; i < arr.length; i++) {
Target target = new Target();
target.setAppId(appId);
target.setAlias(arr[i]);
targets.add(target);
//每50个别名(CID)推送一次
if (arr.length>50&&targets.size()==50){
postData =pushMessageToList(taskId,targets);
Map response = httpResponse(postData);
if (!"ok".equals(response.get("result"))){
response = httpResponse(postData);
respMsg = IfspFastJsonUtil.mapTOjson(response);
log.info("个推建议值推送结果是:"+respMsg);
}
targets.clear();
}
}
if (targets.size()>0){
postData =pushMessageToList(taskId,targets);
Map response = httpResponse(postData);
if (!"ok".equals(response.get("result"))){
response = httpResponse(postData);
respMsg = IfspFastJsonUtil.mapTOjson(response);
log.info("个推第二次推送结果是:"+respMsg);
}
}
}catch (Exception e){
log.error("个推推送失败,原因是:"+e.getMessage());
}
}
public Map pushMessageToList(String contentId, List targetList) throws Exception{
Map postData = new HashMap();
postData.put("authToken", null);
postData.put("action", "pushMessageToListAction");
postData.put("appkey", appKey);
postData.put("contentId", contentId);
boolean needDetails = GTConfig.isPushListNeedDetails();
postData.put("needDetails", needDetails);
boolean async = GTConfig.isPushListAsync();
postData.put("async", async);
boolean needAliasDetails = GTConfig.isPushListNeedAliasDetails();
postData.put("needAliasDetails", needAliasDetails);
int limit;
if (async && !needDetails) {
limit = GTConfig.getAsyncListLimit();
} else {
limit = GTConfig.getSyncListLimit();
}
if (targetList.size() > limit) {
throw new BizException("1000","target size:" + targetList.size() + " beyond the limit:" + limit);
} else {
List clientIdList = new ArrayList();
List aliasList = new ArrayList();
String appId = null;
Iterator var12 = targetList.iterator();
while(true) {
Target target;
do {
if (!var12.hasNext()) {
postData.put("appId", appId);
postData.put("clientIdList", clientIdList);
postData.put("aliasList", aliasList);
postData.put("type", 2);
return postData;
}
target = (Target)var12.next();
String targetCid = target.getClientId();
String targetAlias = target.getAlias();
if (targetCid != null && !"".equals(targetCid.trim())) {
clientIdList.add(targetCid);
} else if (targetAlias != null && !"".equals(targetAlias.trim())) {
aliasList.add(targetAlias);
}
} while(appId != null && !"".equals(appId.trim()));
appId = target.getAppId();
}
}
}
public TransmissionTemplate notificationTemplateDemo(String message) {
// NotificationTemplate template = new NotificationTemplate();
// // 设置APPID与APPKEY
// template.setAppId(appId);
// template.setAppkey(appKey);
// // 设置通知栏标题与内容
// template.setTitle("黔农E付收款通知");
// template.setText(message);
// // 配置通知栏图标
// template.setLogo("icon.png");
// 配置通知栏网络图标
// template.setLogoUrl("");
// 设置通知是否响铃,震动,或者可清除
// template.setIsRing(true);
// template.setIsVibrate(true);
// template.setIsClearable(true);
// 透传消息设置,1为强制启动应用,客户端接收到消息后就会立即启动应用;2为等待应用启动
// template.setTransmissionType(2);
// template.setTransmissionContent(message);
//ios 消息推送
// APNPayload apnPayload = new APNPayload();
// APNPayload.SimpleAlertMsg alertMsg = new APNPayload.SimpleAlertMsg(message);
// apnPayload.setAlertMsg(alertMsg);
// template.setAPNInfo(apnPayload);
// return template;
TransmissionTemplate template = new TransmissionTemplate();
template.setAppId(appId);
template.setAppkey(appKey);
//设置透传消息
template.setTransmissionContent(message);
template.setTransmissionType(2);
//设置三方通知
Notify no = new Notify();
no.setTitle("黔农E付收款通知!");
no.setContent(message);
no.setIntent(""); //客户端生成提供给服务端
no.setType(GtReq.NotifyInfo.Type._intent);
template.set3rdNotifyInfo(no);
//设置ios推送消息
APNPayload payload = new APNPayload();
payload.setBadge(1);
payload.setContentAvailable(1);
payload.setSound("default");
payload.setCategory("$由客户端定义");
//简单模式APNPayload.SimpleMsg
payload.setAlertMsg(new APNPayload.SimpleAlertMsg(message));
//字典模式使用下者
//payload.setAlertMsg(getDictionaryAlertMsg());
template.setAPNInfo(payload);
return template;
}
private String getListAppContentId(Message message, String taskGroupName) {
Map postData = new HashMap();
Map response = null;
if (taskGroupName != null) {
postData.put("taskGroupName", taskGroupName);
}
postData.put("action", "getContentIdAction");
postData.put("appkey", appKey);
postData.put("clientData", Base64Util.getBASE64(message.getData().getTransparent().toByteArray()));
postData.put("transmissionContent", message.getData().getTransmissionContent());
postData.put("isOffline", message.isOffline());
postData.put("offlineExpireTime", message.getOfflineExpireTime());
postData.put("pushType", message.getData().getPushType());
postData.put("type", 2);
if (message instanceof ListMessage) {
postData.put("contentType", 1);
} else if (message instanceof AppMessage) {
postData.put("contentType", 2);
AppMessage appMessage = (AppMessage) message;
ParamUtils.checkAppid(message, appMessage.getAppIdList());
postData.put("appIdList", appMessage.getAppIdList());
List phoneTypeList = null;
List provinceList = null;
List tagList = null;
new ArrayList();
if (appMessage.getConditions() == null) {
phoneTypeList = appMessage.getPhoneTypeList();
provinceList = appMessage.getProvinceList();
tagList = appMessage.getTagList();
postData.put("phoneTypeList", phoneTypeList);
postData.put("provinceList", provinceList);
postData.put("tagList", tagList);
} else {
List
透传模板集成到通知中官方提供文档:
解决接入第三方推送遇到的兼容问题,降低接入成本。
为方便接入了第三方厂商推送的客户,更加简便的使用个推透传模板推送,特别对透传模板进行扩展,使透传模板支持以第三方厂商的通知方式进行下发。目前第三方厂商的通知到达率显著高于第三方透传的到达率。
使用透传模板时,设置notify对象的title, content, intent等参数。
Notify的说明
成员和方法名 |
类型 |
必填 |
说明 |
setTitle |
String |
是 |
通知栏标题 |
setContent |
String |
是 |
通知栏内容 |
setUrl |
String |
否 |
点击通知,打开应用的链接 |
setIntent |
String |
否 |
长度小于1000字节,通知带intent传递参数推荐使用,intent最好由Android开发工程师生成,生成方式见附录 |
setType |
Type |
否 |
取值为(Type._url、Type._intent),如果设置了url、intent,需要指定Type对应的类型;Type所在的包为:com.gexin.rp.sdk.dto.GtReq.NotifyInfo |
public static TransmissionTemplate transmissionTemplateDemo(String appId, String appKey){ TransmissionTemplate template = new TransmissionTemplate(); template.setAppId(appId); template.setAppkey(appKey); template.setTransmissionContent("透传内容"); template.setTransmissionType(2); Notify notify = new Notify(); notify.setTitle("请输入通知栏标题"); notify.setContent("请输入通知栏内容"); notify.setIntent("intent:#Intent;launchFlags=0x10000000;package=com.pp.yl;component=你的包名 /com.getui.demo.MainActivity;i.parm1=12;end"); notify.setType(Type._intent); // notify.setUrl("https://dev.getui.com/"); //notify.setType(Type._url); template.set3rdNotifyInfo(notify);//设置第三方通知 return template; }
|
4. 功能代码示例
Andriod开发工程师生成intent,可以在Android代码中定义一个Intent,然后通过Intent.toUri(Intent.URI_INTENT_SCHEME)获取对应的Intent Uri。
Intent intent = new Intent();
|
5.1生成Intent
如果设置了package,则表示目标应用必须是package所对应的应用。
intent.setPackage("com.getui.demo"); |
component为目标页面的准确activity路径,component中包含应用包名和activity类的全路径。
intent.setComponent(new ComponentName("com.getui.demo", "com.getui.demo.TestActivity")); |
launcherFlags 可指定在启动activity时的启动方式,个推sdk以及厂商sdk在启动activity时会自动设置为FLAG_ACTIVITY_NEW_TASK,所以该设置没有实际意义。
intent.putExtra("stringType", "string"); intent.putExtra("booleanType", true); intent.putExtra("doubleType", 1.0); intent.putExtra("floatType", 1.0f); intent.putExtra("longType", 1L); intent.putExtra("intType", 1); // 还有其他类型的参数可以设置,通过查找`putExtra`方法的重载方法即可 |
可通过intent.putExtra方法设置一系列的参数。
//设置action intent.setAction("android.intent.action.oppopush"); |
由于oppo sdk仅支持通过action的方式打开activity,所以若您的应用需要支持oppo推送(打开指定页面),您需要在intent中设置action,并在AndroidManifet.xml配置对应的action,如下:
android:exported="true"> |
AndroidManifet.xml配置如下:
Log.d(TAG, intent.toUri(Intent.URI_INTENT_SCHEME)); |
打印结果为:intent:#Intent;action=android.intent.action.oppopush;package=com.getui.demo;component=com.getui.demo/com.getui.demo.TestActivity;f.floatType=1.0;l.longType=1;B.booleanType=true;S.stringType=string;d.doubleType=1.0;i.intType=1;end
将生成的intent uri交给服务端开发人员,在对应模板的setIntent方法中设置即可。
=====================三更====================================
使用jmeter测试,发现每次访问个推平台消耗时间大概是300毫秒左右,发送一次推送如果走完所有的流程,需要大概2500毫秒,很耗时间。而且,目前在生产上有用户反馈收不到推送信息,经过排查得知当日的推送消息次数超过了200万次,而多推pushListMessage有这个次数限制。所以需要优化这个推送流程。经过询问个推的开发人员得知,在交互的过程中获取鉴权码,鉴权码的有效期是24个小时,另外接口pushSingleMessage推送是没有次数限制。本次优化的流程思路就是将鉴权码保存到redis中,并设置有效期,推送接口使用单推+多推相结合的方式行优化。目前从测试结果来开个推使用还是有些问题。问题一:个推使用多推时离线发送(只有ios,所谓离线就是退出app页面,个推离线推送的时候会将消息推送给厂商,厂商将消息推送到设备,这个时间不可控,测试环境中,有时间延时,个推厂商给解释说开发环境苹果厂商推送不稳定)会有1~2分钟的时延。问题二:个推使用单推的时候,ios手机推出app,收不到推送消息,个推开发人员解释是开发环境苹果厂商aoip 推送不稳。鉴于这两种给推送结果,目前占时开发出两套优化流程 1. 单推+多推(生产上测试,测试没有问题,优先使用这个),2.多推 (1不行才采用这个方)
优化后代码流程:
1.单推:
2.多推:
优化后代码:
/**
*@author lxw
*@date 2019/12/20
*@desc 安卓群推
*@param alias, message, msgSendType
*@return void
**/
public void IGTandroidPushMsg(String alias,String message){
log.info("安卓用户{}开始推送日志.....",alias);
String respMsg = new String();
String[] arr = alias.split(",");
// 通知透传模板 消息传递
NotificationTemplate nTemplate = notificationTemplateDemo(message);
ListMessage messages = new ListMessage();
messages.setData(nTemplate);
// 设置消息离线,并设置离线时间
messages.setOffline(true);
// 离线有效时间,单位为毫秒,可选
messages.setOfflineExpireTime(24 * 1000 * 3600);
// 配置推送目标
List targets = new ArrayList();
// taskId用于在推送时去查找对应的message
try{
String taskId = getListAppContentId(messages,null);
Map postData = null;
for (int i = 0; i < arr.length; i++) {
Target target = new Target();
target.setAppId(appId);
target.setAlias(arr[i]);
targets.add(target);
//每50个别名(CID)推送一次
if (arr.length>50&&targets.size()==50){
postData =pushMessageToList(taskId,targets);
Map response = httpResponse(postData);
if (!IGParams.PUSH_MSG_OK.equals(response.get("result"))){
response = httpResponse(postData);
respMsg = IfspFastJsonUtil.mapTOjson(response);
}
targets.clear();
}
}
if (targets.size()>0) {
postData = pushMessageToList(taskId, targets);
Map response = httpResponse(postData);
if (IGParams.PUSH_NO_TARGET.equals(response.get("result"))||IGParams.PUSH_MSG_OK.equals(response.get("result"))) {
log.info("用户{}个推推送结果是:" + response.get("result"),alias);
}else {
response = httpResponse(postData);
respMsg = IfspFastJsonUtil.mapTOjson(response);
log.info("用户{}个推第二次推送结果是:" + respMsg,alias);
}
}
}catch (Exception e){
log.error("安卓用户{}推送失败,原因是:"+e.getMessage(),alias);
}
}
/**
*@author lxw
*@date 2019/12/20
*@desc 苹果群推
*@param alias, message, msgSendType
*@return void
**/
public void IGTIosPushMsg(String alias,String message){
log.info("ios用户{}开始推送.....",alias);
String respMsg = new String();
String[] arr = alias.split(",");
//透传模板 消息传递
TransmissionTemplate tTemplate = transmissionTemplateDemo(message);
ListMessage messages = new ListMessage();
messages.setData(tTemplate);
// 设置消息离线,并设置离线时间
messages.setOffline(true);
// 离线有效时间,单位为毫秒,可选
messages.setOfflineExpireTime(24 * 1000 * 3600);
// 配置推送目标
List targets = new ArrayList();
// taskId用于在推送时去查找对应的message
try{
String taskId = getListAppContentId(messages,null);
Map postData = null;
for (int i = 0; i < arr.length; i++) {
Target target = new Target();
target.setAppId(appId);
target.setAlias(arr[i]);
targets.add(target);
//每50个别名(CID)推送一次
if (arr.length>50&&targets.size()==50){
postData =pushMessageToList(taskId,targets);
Map response = httpResponse(postData);
if (!IGParams.PUSH_MSG_OK.equals(response.get("result"))){
response = httpResponse(postData);
respMsg = IfspFastJsonUtil.mapTOjson(response);
}
targets.clear();
}
}
if (targets.size()>0){
postData =pushMessageToList(taskId,targets);
Map response = httpResponse(postData);
if (IGParams.PUSH_NO_TARGET.equals(response.get("result"))||IGParams.PUSH_MSG_OK.equals(response.get("result"))) {
log.info("用户{}个推推送结果是:" + response.get("result"),alias);
}else {
response = httpResponse(postData);
respMsg = IfspFastJsonUtil.mapTOjson(response);
log.info("用户{}再次推送结果是:" + response.get("result"),alias);
}
}
}catch (Exception e){
log.error("ios用户{}推送失败,原因是:"+e.getMessage(),alias);
}
}
/**
*@author lxw
*@date 2019/12/20
*@desc 群推消息参数组装
*@param contentId, targetList
*@return java.util.Map
**/
public Map pushMessageToList(String contentId, List targetList) throws Exception{
log.info("pushMessageToList组装推送参数开始,用户taskid:{}。。。。",contentId);
Map postData = new HashMap();
postData.put("authToken", getAuthTokenCache().opsForValue().get("authToken")==null?"":getAuthTokenCache().opsForValue().get("authToken"));
postData.put("action", "pushMessageToListAction");
postData.put("appkey", appKey);
postData.put("contentId", contentId);
boolean needDetails = GTConfig.isPushListNeedDetails();
postData.put("needDetails", needDetails);
boolean async = GTConfig.isPushListAsync();
postData.put("async", async);
boolean needAliasDetails = GTConfig.isPushListNeedAliasDetails();
postData.put("needAliasDetails", needAliasDetails);
int limit;
if (async && !needDetails) {
limit = GTConfig.getAsyncListLimit();
} else {
limit = GTConfig.getSyncListLimit();
}
if (targetList.size() > limit) {
throw new BizException("1000","target size:" + targetList.size() + " beyond the limit:" + limit);
} else {
List clientIdList = new ArrayList();
List aliasList = new ArrayList();
String appId = null;
Iterator var12 = targetList.iterator();
while(true) {
Target target;
do {
if (!var12.hasNext()) {
postData.put("appId", appId);
postData.put("clientIdList", clientIdList);
postData.put("aliasList", aliasList);
postData.put("type", 2);
return postData;
}
target = (Target)var12.next();
String targetCid = target.getClientId();
String targetAlias = target.getAlias();
if (targetCid != null && !"".equals(targetCid.trim())) {
clientIdList.add(targetCid);
} else if (targetAlias != null && !"".equals(targetAlias.trim())) {
aliasList.add(targetAlias);
}
} while(appId != null && !"".equals(appId.trim()));
appId = target.getAppId();
}
}
}
//通知消息
public NotificationTemplate notificationTemplateDemo(String message) {
NotificationTemplate template = new NotificationTemplate();
// 设置APPID与APPKEY
template.setAppId(appId);
template.setAppkey(appKey);
Style0 style = new Style0();
style.setTitle("黔农E付收款通知");
// 设置通知栏标题与内容
style.setText(message);
// 配置通知栏网络图标
style.setLogo("icon.png");
// 设置通知是否响铃,震动,或者可清除
style.setRing(true);
style.setVibrate(true);
style.setClearable(true);
// 透传消息设置,1为强制启动应用,客户端接收到消息后就会立即启动应用;2为等待应用启动
template.setTransmissionType(1);
template.setTransmissionContent(message);
template.setStyle(style);
return template;
}
//透传消息
public TransmissionTemplate transmissionTemplateDemo(String message) {
Map msgMap = new HashMap<>();
msgMap.put("黔农商户宝",message);
TransmissionTemplate template = new TransmissionTemplate();
template.setAppId(appId);
template.setAppkey(appKey);
//透传消息设置
template.setTransmissionContent(IfspFastJsonUtil.mapTOjson(msgMap));
template.setTransmissionType(2);
//ios 消息推送
APNPayload payload = new APNPayload();
payload.setAutoBadge("1");
payload.setContentAvailable(0);
payload.setVoicePlayType(1);
payload.setSound("default");
payload.setCategory("$由客户端定义");
VoIPPayload voIPPayload = new VoIPPayload();
Map vp = new HashMap<>();
vp.put("titile","黔农E付收款通知");
vp.put("message",message);
vp.put("payload","payload");
voIPPayload.setVoIPPayload(IfspFastJsonUtil.mapTOjson(vp));
template.setAPNInfo(voIPPayload);
return template;
}
//获取群推的taskid
private String getListAppContentId(Message message, String taskGroupName) {
Map postData = new HashMap();
Map response = null;
if (taskGroupName != null) {
postData.put("taskGroupName", taskGroupName);
}
postData.put("action", "getContentIdAction");
postData.put("appkey", appKey);
postData.put("clientData", Base64Util.getBASE64(message.getData().getTransparent().toByteArray()));
postData.put("transmissionContent", message.getData().getTransmissionContent());
postData.put("isOffline", message.isOffline());
postData.put("offlineExpireTime", message.getOfflineExpireTime());
postData.put("pushType", message.getData().getPushType());
postData.put("type", 2);
if (message instanceof ListMessage) {
postData.put("contentType", 1);
} else if (message instanceof AppMessage) {
postData.put("contentType", 2);
AppMessage appMessage = (AppMessage) message;
ParamUtils.checkAppid(message, appMessage.getAppIdList());
postData.put("appIdList", appMessage.getAppIdList());
List phoneTypeList = null;
List provinceList = null;
List tagList = null;
new ArrayList();
if (appMessage.getConditions() == null) {
phoneTypeList = appMessage.getPhoneTypeList();
provinceList = appMessage.getProvinceList();
tagList = appMessage.getTagList();
postData.put("phoneTypeList", phoneTypeList);
postData.put("provinceList", provinceList);
postData.put("tagList", tagList);
} else {
List
http 链接还是使用最上方的链接
工具类:
public Static final String PUSH_SIGN_ERROR="sign_error";
public Static final String PUSH_NO_TARGET="NOTarget";
public Static final String PUSH_MSG_OK="ok";
总结:
1.目前生产使用模式是单推+多推结合的方式。
2.个推推送分为 离线推送、在线推送,在线推送是指 个推平台将消息推送给手机,离线推送是指 个推将消息推送给手机厂商,由厂商来推送消息。区分是离线推送还是在线推送,可以查看推送成功后的响应报文中有个推送状态,那里会显示是离线推送还是在线推送。
3.手机接收不到消息问题排查
3.1:核对配置参数是否正确(appId,appKey,masterScript.....);
3.2:如果是使用别名推送,查看推送是否绑定了cid(个推为每个手机设备分配的识别码,每个手机只能生成一个,不会变);个推平台提供了方法查询别名下绑定的cid 个数,每个别名只能绑定10个cid。别名绑定超过10时候,新绑定的cid 会将已经绑定的cid其中一个顶掉。别名下cid 查询:
import com.gexin.rp.sdk.base.IAliasResult;
import com.gexin.rp.sdk.http.IGtPush;
public class GETTUIaLIAS {
private static String appId = "QFoBXS1TrJ9yc";//个推上配置的appId
private static String appKey = "M2FJjXxnP3Ark";//个推上配置的appKey
private static String masterSecret = "aWU9lqy8CX6EP";//个推上配置的masterSecret
static String host = "http://sdk.open.api.igexin.com/apiex.htm";
public static void main(String[] args) {
String Alias = "8201807060000001_13641064684";//要查询的别名
IGtPush push = new IGtPush(host, appKey, masterSecret);
IAliasResult queryClient = push.queryClientId(appId, Alias);
System.out.println("根据别名获取的CID:" + queryClient.getClientIdList());
}
}
,服务端是获取不到每个手机的cid ,需要客户端(app端) 来获取cid。查看cid 所属苹果或者安卓可以去个推平台
中,输入别名下查询出cid ,就可以查看出手机型号和所属手机厂商。