commit push server
This commit is contained in:
11
src/main/java/cn/wildfirechat/push/PushApplication.java
Normal file
11
src/main/java/cn/wildfirechat/push/PushApplication.java
Normal file
@@ -0,0 +1,11 @@
|
||||
package cn.wildfirechat.push;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class PushApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(PushApplication.class, args);
|
||||
}
|
||||
}
|
||||
28
src/main/java/cn/wildfirechat/push/PushController.java
Normal file
28
src/main/java/cn/wildfirechat/push/PushController.java
Normal file
@@ -0,0 +1,28 @@
|
||||
package cn.wildfirechat.push;
|
||||
|
||||
import cn.wildfirechat.push.android.AndroidPushService;
|
||||
import cn.wildfirechat.push.ios.IOSPushService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class PushController {
|
||||
|
||||
@Autowired
|
||||
private AndroidPushService mAndroidPushService;
|
||||
|
||||
@Autowired
|
||||
private IOSPushService mIOSPushService;
|
||||
|
||||
@PostMapping(value = "/android/push", produces = "application/json;charset=UTF-8" )
|
||||
public Object androidPush(@RequestBody PushMessage pushMessage) {
|
||||
return mAndroidPushService.push(pushMessage);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/ios/push", produces = "application/json;charset=UTF-8" )
|
||||
public Object iOSPush(@RequestBody PushMessage pushMessage) {
|
||||
return mIOSPushService.push(pushMessage);
|
||||
}
|
||||
}
|
||||
161
src/main/java/cn/wildfirechat/push/PushMessage.java
Normal file
161
src/main/java/cn/wildfirechat/push/PushMessage.java
Normal file
@@ -0,0 +1,161 @@
|
||||
package cn.wildfirechat.push;
|
||||
|
||||
|
||||
public class PushMessage {
|
||||
public String sender;
|
||||
public String senderName;
|
||||
public int convType;
|
||||
public String target;
|
||||
public String targetName;
|
||||
public int line;
|
||||
public int cntType;
|
||||
public long serverTime;
|
||||
//消息的类型,普通消息通知栏;voip要透传。
|
||||
public int pushMessageType;
|
||||
//推送类型,android推送分为小米/华为/魅族等。ios分别为开发和发布。
|
||||
public int pushType;
|
||||
public String pushContent;
|
||||
public int unReceivedMsg;
|
||||
public int mentionedType;
|
||||
public String packageName;
|
||||
public String deviceToken;
|
||||
public String voipDeviceToken;
|
||||
public String language;
|
||||
|
||||
|
||||
public String getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public void setSender(String sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public String getSenderName() {
|
||||
return senderName;
|
||||
}
|
||||
|
||||
public void setSenderName(String senderName) {
|
||||
this.senderName = senderName;
|
||||
}
|
||||
|
||||
public int getConvType() {
|
||||
return convType;
|
||||
}
|
||||
|
||||
public void setConvType(int convType) {
|
||||
this.convType = convType;
|
||||
}
|
||||
|
||||
public String getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget(String target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public String getTargetName() {
|
||||
return targetName;
|
||||
}
|
||||
|
||||
public void setTargetName(String targetName) {
|
||||
this.targetName = targetName;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public void setLine(int line) {
|
||||
this.line = line;
|
||||
}
|
||||
|
||||
public int getCntType() {
|
||||
return cntType;
|
||||
}
|
||||
|
||||
public void setCntType(int cntType) {
|
||||
this.cntType = cntType;
|
||||
}
|
||||
|
||||
public long getServerTime() {
|
||||
return serverTime;
|
||||
}
|
||||
|
||||
public void setServerTime(long serverTime) {
|
||||
this.serverTime = serverTime;
|
||||
}
|
||||
|
||||
public int getPushMessageType() {
|
||||
return pushMessageType;
|
||||
}
|
||||
|
||||
public void setPushMessageType(int pushMessageType) {
|
||||
this.pushMessageType = pushMessageType;
|
||||
}
|
||||
|
||||
public int getPushType() {
|
||||
return pushType;
|
||||
}
|
||||
|
||||
public void setPushType(int pushType) {
|
||||
this.pushType = pushType;
|
||||
}
|
||||
|
||||
public String getPushContent() {
|
||||
return pushContent;
|
||||
}
|
||||
|
||||
public void setPushContent(String pushContent) {
|
||||
this.pushContent = pushContent;
|
||||
}
|
||||
|
||||
public int getUnReceivedMsg() {
|
||||
return unReceivedMsg;
|
||||
}
|
||||
|
||||
public void setUnReceivedMsg(int unReceivedMsg) {
|
||||
this.unReceivedMsg = unReceivedMsg;
|
||||
}
|
||||
|
||||
public int getMentionedType() {
|
||||
return mentionedType;
|
||||
}
|
||||
|
||||
public void setMentionedType(int mentionedType) {
|
||||
this.mentionedType = mentionedType;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return packageName;
|
||||
}
|
||||
|
||||
public void setPackageName(String packageName) {
|
||||
this.packageName = packageName;
|
||||
}
|
||||
|
||||
public String getDeviceToken() {
|
||||
return deviceToken;
|
||||
}
|
||||
|
||||
public void setDeviceToken(String deviceToken) {
|
||||
this.deviceToken = deviceToken;
|
||||
}
|
||||
|
||||
public String getVoipDeviceToken() {
|
||||
return voipDeviceToken;
|
||||
}
|
||||
|
||||
public void setVoipDeviceToken(String voipDeviceToken) {
|
||||
this.voipDeviceToken = voipDeviceToken;
|
||||
}
|
||||
|
||||
public String getLanguage() {
|
||||
return language;
|
||||
}
|
||||
|
||||
public void setLanguage(String language) {
|
||||
this.language = language;
|
||||
}
|
||||
}
|
||||
7
src/main/java/cn/wildfirechat/push/PushMessageType.java
Normal file
7
src/main/java/cn/wildfirechat/push/PushMessageType.java
Normal file
@@ -0,0 +1,7 @@
|
||||
package cn.wildfirechat.push;
|
||||
|
||||
public interface PushMessageType {
|
||||
int PUSH_MESSAGE_TYPE_NORMAL = 0;
|
||||
int PUSH_MESSAGE_TYPE_VOIP_INVITE = 1;
|
||||
int PUSH_MESSAGE_TYPE_VOIP_BYE = 2;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package cn.wildfirechat.push.android;
|
||||
|
||||
import cn.wildfirechat.push.PushMessage;
|
||||
|
||||
public interface AndroidPushService {
|
||||
Object push(PushMessage pushMessage);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package cn.wildfirechat.push.android;
|
||||
|
||||
import cn.wildfirechat.push.PushMessage;
|
||||
import cn.wildfirechat.push.android.hms.HMSPush;
|
||||
import cn.wildfirechat.push.android.meizu.MeiZuPush;
|
||||
import cn.wildfirechat.push.android.xiaomi.XiaomiPush;
|
||||
import com.google.gson.Gson;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class AndroidPushServiceImpl implements AndroidPushService {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AndroidPushServiceImpl.class);
|
||||
@Autowired
|
||||
private HMSPush hmsPush;
|
||||
|
||||
@Autowired
|
||||
private MeiZuPush meiZuPush;
|
||||
|
||||
@Autowired
|
||||
private XiaomiPush xiaomiPush;
|
||||
|
||||
|
||||
@Override
|
||||
public Object push(PushMessage pushMessage) {
|
||||
LOG.info("Android push {}", new Gson().toJson(pushMessage));
|
||||
switch (pushMessage.getPushType()) {
|
||||
case AndroidPushType.ANDROID_PUSH_TYPE_XIAOMI:
|
||||
xiaomiPush.push(pushMessage);
|
||||
break;
|
||||
case AndroidPushType.ANDROID_PUSH_TYPE_HUAWEI:
|
||||
hmsPush.push(pushMessage);
|
||||
break;
|
||||
case AndroidPushType.ANDROID_PUSH_TYPE_MEIZU:
|
||||
meiZuPush.push(pushMessage);
|
||||
break;
|
||||
default:
|
||||
LOG.info("unknown push type");
|
||||
break;
|
||||
}
|
||||
return "ok";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package cn.wildfirechat.push.android;
|
||||
|
||||
public interface AndroidPushType {
|
||||
int ANDROID_PUSH_TYPE_XIAOMI = 1;
|
||||
int ANDROID_PUSH_TYPE_HUAWEI = 2;
|
||||
int ANDROID_PUSH_TYPE_MEIZU = 3;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.wildfirechat.push.android.hms;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix="hms")
|
||||
@PropertySource(value = "classpath:hms.properties")
|
||||
public class HMSConfig {
|
||||
private String appSecret;
|
||||
private String appId;
|
||||
|
||||
public String getAppSecret() {
|
||||
return appSecret;
|
||||
}
|
||||
|
||||
public void setAppSecret(String appSecret) {
|
||||
this.appSecret = appSecret;
|
||||
}
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
}
|
||||
136
src/main/java/cn/wildfirechat/push/android/hms/HMSPush.java
Normal file
136
src/main/java/cn/wildfirechat/push/android/hms/HMSPush.java
Normal file
@@ -0,0 +1,136 @@
|
||||
package cn.wildfirechat.push.android.hms;
|
||||
|
||||
|
||||
import cn.wildfirechat.push.PushMessage;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
public class HMSPush {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HMSPush.class);
|
||||
private static final String tokenUrl = "https://login.vmall.com/oauth2/token"; //获取认证Token的URL
|
||||
private static final String apiUrl = "https://api.push.hicloud.com/pushsend.do"; //应用级消息下发API
|
||||
private String accessToken;//下发通知消息的认证Token
|
||||
private long tokenExpiredTime; //accessToken的过期时间
|
||||
|
||||
@Autowired
|
||||
private HMSConfig mConfig;
|
||||
|
||||
//获取下发通知消息的认证Token
|
||||
private void refreshToken() throws IOException {
|
||||
LOG.info("hms refresh token");
|
||||
String msgBody = MessageFormat.format(
|
||||
"grant_type=client_credentials&client_secret={0}&client_id={1}",
|
||||
URLEncoder.encode(mConfig.getAppSecret(), "UTF-8"), mConfig.getAppId());
|
||||
String response = httpPost(tokenUrl, msgBody, 5000, 5000);
|
||||
JSONObject obj = JSONObject.parseObject(response);
|
||||
accessToken = obj.getString("access_token");
|
||||
tokenExpiredTime = System.currentTimeMillis() + obj.getLong("expires_in") - 5*60*1000;
|
||||
LOG.info("hms refresh token with result {}", response);
|
||||
}
|
||||
|
||||
//发送Push消息
|
||||
public void push(PushMessage pushMessage) {
|
||||
if (tokenExpiredTime <= System.currentTimeMillis()) {
|
||||
try {
|
||||
refreshToken();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
/*PushManager.requestToken为客户端申请token的方法,可以调用多次以防止申请token失败*/
|
||||
/*PushToken不支持手动编写,需使用客户端的onToken方法获取*/
|
||||
JSONArray deviceTokens = new JSONArray();//目标设备Token
|
||||
deviceTokens.add(pushMessage.getDeviceToken());
|
||||
|
||||
|
||||
JSONObject msg = new JSONObject();
|
||||
msg.put("type", 1);//3: 通知栏消息,异步透传消息请根据接口文档设置
|
||||
msg.put("body", new Gson().toJson(pushMessage));//通知栏消息body内容
|
||||
|
||||
JSONObject hps = new JSONObject();//华为PUSH消息总结构体
|
||||
hps.put("msg", msg);
|
||||
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("hps", hps);
|
||||
|
||||
LOG.info("send push to HMS {}", payload);
|
||||
|
||||
try {
|
||||
String postBody = MessageFormat.format(
|
||||
"access_token={0}&nsp_svc={1}&nsp_ts={2}&device_token_list={3}&payload={4}",
|
||||
URLEncoder.encode(accessToken,"UTF-8"),
|
||||
URLEncoder.encode("openpush.message.api.send","UTF-8"),
|
||||
URLEncoder.encode(String.valueOf(System.currentTimeMillis() / 1000),"UTF-8"),
|
||||
URLEncoder.encode(deviceTokens.toString(),"UTF-8"),
|
||||
URLEncoder.encode(payload.toString(),"UTF-8"));
|
||||
|
||||
String postUrl = apiUrl + "?nsp_ctx=" + URLEncoder.encode("{\"ver\":\"1\", \"appId\":\"" + mConfig.getAppId() + "\"}", "UTF-8");
|
||||
String response = httpPost(postUrl, postBody, 5000, 5000);
|
||||
LOG.info("Push to {} response {}", pushMessage.getDeviceToken(), response);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
LOG.info("Push to {} with exception", pushMessage.getDeviceToken(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public String httpPost(String httpUrl, String data, int connectTimeout, int readTimeout) throws IOException {
|
||||
OutputStream outPut = null;
|
||||
HttpURLConnection urlConnection = null;
|
||||
InputStream in = null;
|
||||
|
||||
try {
|
||||
URL url = new URL(httpUrl);
|
||||
urlConnection = (HttpURLConnection)url.openConnection();
|
||||
urlConnection.setRequestMethod("POST");
|
||||
urlConnection.setDoOutput(true);
|
||||
urlConnection.setDoInput(true);
|
||||
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
|
||||
urlConnection.setConnectTimeout(connectTimeout);
|
||||
urlConnection.setReadTimeout(readTimeout);
|
||||
urlConnection.connect();
|
||||
|
||||
// POST data
|
||||
outPut = urlConnection.getOutputStream();
|
||||
outPut.write(data.getBytes("UTF-8"));
|
||||
outPut.flush();
|
||||
|
||||
// read response
|
||||
if (urlConnection.getResponseCode() < 400) {
|
||||
in = urlConnection.getInputStream();
|
||||
} else {
|
||||
in = urlConnection.getErrorStream();
|
||||
}
|
||||
|
||||
List<String> lines = IOUtils.readLines(in, urlConnection.getContentEncoding());
|
||||
StringBuffer strBuf = new StringBuffer();
|
||||
for (String line : lines) {
|
||||
strBuf.append(line);
|
||||
}
|
||||
LOG.info(strBuf.toString());
|
||||
return strBuf.toString();
|
||||
}
|
||||
finally {
|
||||
IOUtils.closeQuietly(outPut);
|
||||
IOUtils.closeQuietly(in);
|
||||
if (urlConnection != null) {
|
||||
urlConnection.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package cn.wildfirechat.push.android.meizu;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix="meizu")
|
||||
@PropertySource(value = "classpath:meizu.properties")
|
||||
public class MeiZuConfig {
|
||||
private String appSecret;
|
||||
private long appId;
|
||||
|
||||
public String getAppSecret() {
|
||||
return appSecret;
|
||||
}
|
||||
|
||||
public void setAppSecret(String appSecret) {
|
||||
this.appSecret = appSecret;
|
||||
}
|
||||
|
||||
public long getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(long appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package cn.wildfirechat.push.android.meizu;
|
||||
|
||||
import cn.wildfirechat.push.PushMessage;
|
||||
import com.meizu.push.sdk.server.IFlymePush;
|
||||
import com.meizu.push.sdk.server.constant.ResultPack;
|
||||
import com.meizu.push.sdk.server.model.push.PushResult;
|
||||
import com.meizu.push.sdk.server.model.push.VarnishedMessage;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
public class MeiZuPush {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MeiZuPush.class);
|
||||
private IFlymePush flymePush;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
this.flymePush = new IFlymePush(mConfig.getAppSecret());
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private MeiZuConfig mConfig;
|
||||
|
||||
public void push(PushMessage pushMessage) {
|
||||
//组装透传消息
|
||||
VarnishedMessage message = new VarnishedMessage.Builder()
|
||||
.appId(mConfig.getAppId())
|
||||
.title("WildfireChat")
|
||||
.content(pushMessage.pushContent)
|
||||
.validTime(1)
|
||||
.build();
|
||||
|
||||
//目标用户
|
||||
List<String> pushIds = new ArrayList<String>();
|
||||
pushIds.add(pushMessage.getDeviceToken());
|
||||
|
||||
try {
|
||||
// 1 调用推送服务
|
||||
ResultPack<PushResult> result = flymePush.pushMessage(message, pushIds);
|
||||
if (result.isSucceed()) {
|
||||
// 2 调用推送服务成功 (其中map为设备的具体推送结果,一般业务针对超速的code类型做处理)
|
||||
PushResult pushResult = result.value();
|
||||
String msgId = pushResult.getMsgId();//推送消息ID,用于推送流程明细排查
|
||||
Map<String, List<String>> targetResultMap = pushResult.getRespTarget();//推送结果,全部推送成功,则map为empty
|
||||
LOG.info("push result:" + pushResult);
|
||||
if (targetResultMap != null && !targetResultMap.isEmpty()) {
|
||||
System.err.println("push fail token:" + targetResultMap);
|
||||
}
|
||||
} else {
|
||||
// 调用推送接口服务异常 eg: appId、appKey非法、推送消息非法.....
|
||||
// result.code(); //服务异常码
|
||||
// result.comment();//服务异常描述
|
||||
LOG.info(String.format("pushMessage error code:%s comment:%s", result.code(), result.comment()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package cn.wildfirechat.push.android.xiaomi;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix="xiaomi")
|
||||
@PropertySource(value = "classpath:xiaomi.properties")
|
||||
public class XiaomiConfig {
|
||||
private String appSecret;
|
||||
|
||||
public String getAppSecret() {
|
||||
return appSecret;
|
||||
}
|
||||
|
||||
public void setAppSecret(String appSecret) {
|
||||
this.appSecret = appSecret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package cn.wildfirechat.push.android.xiaomi;
|
||||
|
||||
|
||||
import cn.wildfirechat.push.PushMessage;
|
||||
import cn.wildfirechat.push.PushMessageType;
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaomi.xmpush.server.Constants;
|
||||
import com.xiaomi.xmpush.server.Message;
|
||||
import com.xiaomi.xmpush.server.Result;
|
||||
import com.xiaomi.xmpush.server.Sender;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.json.simple.parser.ParseException;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static com.xiaomi.xmpush.server.Message.NOTIFY_TYPE_ALL;
|
||||
|
||||
@Component
|
||||
public class XiaomiPush {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(XiaomiPush.class);
|
||||
@Autowired
|
||||
private XiaomiConfig mConfig;
|
||||
|
||||
|
||||
public void push(PushMessage pushMessage) {
|
||||
Constants.useOfficial();
|
||||
Sender sender = new Sender(mConfig.getAppSecret());
|
||||
|
||||
Message message;
|
||||
if(pushMessage.pushMessageType != PushMessageType.PUSH_MESSAGE_TYPE_NORMAL) {
|
||||
//voip
|
||||
long timeToLive = 60 * 1000; // 1 min
|
||||
message = new Message.Builder()
|
||||
.payload(new Gson().toJson(pushMessage))
|
||||
.restrictedPackageName(pushMessage.getPackageName())
|
||||
.passThrough(1) //透传
|
||||
.timeToLive(timeToLive)
|
||||
.enableFlowControl(false)
|
||||
.build();
|
||||
} else {
|
||||
long timeToLive = 600 * 1000;//10 min
|
||||
message = new Message.Builder()
|
||||
.payload(new Gson().toJson(pushMessage))
|
||||
.title("新消息提醒")
|
||||
.description(pushMessage.pushContent)
|
||||
.notifyType(NOTIFY_TYPE_ALL)
|
||||
.restrictedPackageName(pushMessage.getPackageName())
|
||||
.passThrough(0)
|
||||
.timeToLive(timeToLive)
|
||||
.enableFlowControl(true)
|
||||
.build();
|
||||
}
|
||||
|
||||
Result result = null;
|
||||
try {
|
||||
result = sender.send(message, pushMessage.getDeviceToken(), 3);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ParseException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
LOG.info("Server response: MessageId: " + result.getMessageId()
|
||||
+ " ErrorCode: " + result.getErrorCode().toString()
|
||||
+ " Reason: " + result.getReason());
|
||||
}
|
||||
}
|
||||
86
src/main/java/cn/wildfirechat/push/ios/ApnsConfig.java
Normal file
86
src/main/java/cn/wildfirechat/push/ios/ApnsConfig.java
Normal file
@@ -0,0 +1,86 @@
|
||||
package cn.wildfirechat.push.ios;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix="apns")
|
||||
@PropertySource(value = "classpath:apns.properties")
|
||||
public class ApnsConfig {
|
||||
String productCerPath;
|
||||
String productCerPwd;
|
||||
|
||||
String developCerPath;
|
||||
String developCerPwd;
|
||||
|
||||
String voipCerPath;
|
||||
String voipCerPwd;
|
||||
|
||||
String alert;
|
||||
String voipAlert;
|
||||
|
||||
public String getProductCerPath() {
|
||||
return productCerPath;
|
||||
}
|
||||
|
||||
public void setProductCerPath(String productCerPath) {
|
||||
this.productCerPath = productCerPath;
|
||||
}
|
||||
|
||||
public String getProductCerPwd() {
|
||||
return productCerPwd;
|
||||
}
|
||||
|
||||
public void setProductCerPwd(String productCerPwd) {
|
||||
this.productCerPwd = productCerPwd;
|
||||
}
|
||||
|
||||
public String getDevelopCerPath() {
|
||||
return developCerPath;
|
||||
}
|
||||
|
||||
public void setDevelopCerPath(String developCerPath) {
|
||||
this.developCerPath = developCerPath;
|
||||
}
|
||||
|
||||
public String getDevelopCerPwd() {
|
||||
return developCerPwd;
|
||||
}
|
||||
|
||||
public void setDevelopCerPwd(String developCerPwd) {
|
||||
this.developCerPwd = developCerPwd;
|
||||
}
|
||||
|
||||
public String getVoipCerPath() {
|
||||
return voipCerPath;
|
||||
}
|
||||
|
||||
public void setVoipCerPath(String voipCerPath) {
|
||||
this.voipCerPath = voipCerPath;
|
||||
}
|
||||
|
||||
public String getVoipCerPwd() {
|
||||
return voipCerPwd;
|
||||
}
|
||||
|
||||
public void setVoipCerPwd(String voipCerPwd) {
|
||||
this.voipCerPwd = voipCerPwd;
|
||||
}
|
||||
|
||||
public String getAlert() {
|
||||
return alert;
|
||||
}
|
||||
|
||||
public void setAlert(String alert) {
|
||||
this.alert = alert;
|
||||
}
|
||||
|
||||
public String getVoipAlert() {
|
||||
return voipAlert;
|
||||
}
|
||||
|
||||
public void setVoipAlert(String voipAlert) {
|
||||
this.voipAlert = voipAlert;
|
||||
}
|
||||
}
|
||||
187
src/main/java/cn/wildfirechat/push/ios/ApnsServer.java
Normal file
187
src/main/java/cn/wildfirechat/push/ios/ApnsServer.java
Normal file
@@ -0,0 +1,187 @@
|
||||
package cn.wildfirechat.push.ios;
|
||||
|
||||
import cn.wildfirechat.push.PushMessage;
|
||||
import cn.wildfirechat.push.PushMessageType;
|
||||
import com.notnoop.apns.*;
|
||||
import com.notnoop.exceptions.ApnsDeliveryErrorException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.notnoop.apns.DeliveryError.INVALID_TOKEN;
|
||||
|
||||
@Component
|
||||
public class ApnsServer implements ApnsDelegate {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ApnsServer.class);
|
||||
@Override
|
||||
public void messageSent(ApnsNotification message, boolean resent) {
|
||||
LOG.info("APNS push sent:{}", message.getDeviceToken());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageSendFailed(ApnsNotification message, Throwable e) {
|
||||
LOG.info("APNS push failure:{}", e.getMessage());
|
||||
if(e instanceof ApnsDeliveryErrorException) {
|
||||
ApnsDeliveryErrorException apnsDeliveryErrorException = (ApnsDeliveryErrorException)e;
|
||||
LOG.info("APNS error code:{}", apnsDeliveryErrorException.getDeliveryError());
|
||||
if (apnsDeliveryErrorException.getDeliveryError() == INVALID_TOKEN) {
|
||||
if (message.getDeviceId() != null) {
|
||||
LOG.error("Invalide token!!!");
|
||||
} else {
|
||||
LOG.error("APNS ERROR without deviceId:{}", message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connectionClosed(DeliveryError e, int messageIdentifier) {
|
||||
LOG.info("111");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cacheLengthExceeded(int newCacheLength) {
|
||||
LOG.info("111");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notificationsResent(int resendCount) {
|
||||
LOG.info("111");
|
||||
}
|
||||
|
||||
ApnsService productSvc;
|
||||
ApnsService developSvc;
|
||||
ApnsService voipSvc;
|
||||
|
||||
@Autowired
|
||||
private ApnsConfig mConfig;
|
||||
|
||||
@PostConstruct
|
||||
private void init() {
|
||||
if (StringUtils.isEmpty(mConfig.alert)) {
|
||||
mConfig.alert = "default";
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(mConfig.voipAlert)) {
|
||||
mConfig.alert = "default";
|
||||
}
|
||||
|
||||
productSvc = APNS.newService()
|
||||
.asBatched(3, 10)
|
||||
.withAppleDestination(true)
|
||||
.withCert(mConfig.productCerPath, mConfig.productCerPwd)
|
||||
.withDelegate(this)
|
||||
.build();
|
||||
|
||||
developSvc = APNS.newService()
|
||||
.asBatched(3, 10)
|
||||
.withAppleDestination(false)
|
||||
.withCert(mConfig.developCerPath, mConfig.developCerPwd)
|
||||
.withDelegate(this)
|
||||
.build();
|
||||
|
||||
voipSvc = APNS.newService()
|
||||
.withAppleDestination(true)
|
||||
.withCert(mConfig.voipCerPath, mConfig.voipCerPwd)
|
||||
.withDelegate(this)
|
||||
.build();
|
||||
|
||||
productSvc.start();
|
||||
developSvc.start();
|
||||
voipSvc.start();
|
||||
}
|
||||
|
||||
|
||||
public void pushMessage(PushMessage pushMessage) {
|
||||
|
||||
ApnsService service = developSvc;
|
||||
if (pushMessage.getPushType() == IOSPushType.IOS_PUSH_TYPE_DISTRIBUTION) {
|
||||
if (pushMessage.pushMessageType == PushMessageType.PUSH_MESSAGE_TYPE_NORMAL || StringUtils.isEmpty(pushMessage.getVoipDeviceToken())) {
|
||||
service = productSvc;
|
||||
} else {
|
||||
service = voipSvc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (service == null) {
|
||||
LOG.error("Service not exist!!!!");
|
||||
return;
|
||||
}
|
||||
String sound = mConfig.alert;
|
||||
|
||||
String pushContent = pushMessage.getPushContent();
|
||||
if (pushMessage.pushMessageType == PushMessageType.PUSH_MESSAGE_TYPE_VOIP_INVITE) {
|
||||
pushContent = "通话邀请";
|
||||
sound = mConfig.voipAlert;
|
||||
} else if(pushMessage.pushMessageType == PushMessageType.PUSH_MESSAGE_TYPE_VOIP_BYE) {
|
||||
pushContent = "通话结束";
|
||||
sound = null;
|
||||
}
|
||||
|
||||
int badge = pushMessage.getUnReceivedMsg();
|
||||
if (badge <= 0) {
|
||||
badge = 1;
|
||||
}
|
||||
|
||||
String title;
|
||||
String body;
|
||||
//todo 这里需要加上语言的处理,客户端会上报自己的语言,在DeviceInfo那个类中
|
||||
// if (pushMessage.language == "zh_CN") {
|
||||
//
|
||||
// } else if(pushMessage.language == "US_EN") {
|
||||
//
|
||||
// }
|
||||
if (pushMessage.convType == 1) {
|
||||
title = pushMessage.targetName;
|
||||
if (StringUtils.isEmpty(title)) {
|
||||
title = "群聊";
|
||||
}
|
||||
|
||||
if (StringUtils.isEmpty(pushMessage.senderName)) {
|
||||
body = pushContent;
|
||||
} else {
|
||||
body = pushMessage.senderName + ":" + pushContent;
|
||||
}
|
||||
|
||||
if (pushMessage.mentionedType == 1) {
|
||||
if (StringUtils.isEmpty(pushMessage.senderName)) {
|
||||
body = "有人在群里@了你";
|
||||
} else {
|
||||
body = pushMessage.senderName + "在群里@了你";
|
||||
}
|
||||
} else if(pushMessage.mentionedType == 2) {
|
||||
if (StringUtils.isEmpty(pushMessage.senderName)) {
|
||||
body = "有人在群里@了大家";
|
||||
} else {
|
||||
body = pushMessage.senderName + "在群里@了大家";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (StringUtils.isEmpty(pushMessage.senderName)) {
|
||||
title = "消息";
|
||||
} else {
|
||||
title = pushMessage.senderName;
|
||||
}
|
||||
body = pushContent;
|
||||
}
|
||||
|
||||
final String payload = APNS.newPayload().alertBody(body).badge(badge).alertTitle(title).sound(sound).build();
|
||||
final ApnsNotification goodMsg = service.push(service == voipSvc ? pushMessage.getVoipDeviceToken() : pushMessage.getDeviceToken(), payload, null);
|
||||
LOG.info("Message id: " + goodMsg.getIdentifier());
|
||||
|
||||
|
||||
//检查key到期日期
|
||||
final Map<String, Date> inactiveDevices = service.getInactiveDevices();
|
||||
for (final Map.Entry<String, Date> ent : inactiveDevices.entrySet()) {
|
||||
LOG.info("Inactive " + ent.getKey() + " at date " + ent.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package cn.wildfirechat.push.ios;
|
||||
|
||||
import cn.wildfirechat.push.PushMessage;
|
||||
|
||||
public interface IOSPushService {
|
||||
Object push(PushMessage pushMessage);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.wildfirechat.push.ios;
|
||||
|
||||
import cn.wildfirechat.push.PushMessage;
|
||||
import com.google.gson.Gson;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class IOSPushServiceImpl implements IOSPushService {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(IOSPushServiceImpl.class);
|
||||
@Autowired
|
||||
public ApnsServer apnsServer;
|
||||
|
||||
@Override
|
||||
public Object push(PushMessage pushMessage) {
|
||||
LOG.info("iOS push {}", new Gson().toJson(pushMessage));
|
||||
apnsServer.pushMessage(pushMessage);
|
||||
return "OK";
|
||||
}
|
||||
}
|
||||
6
src/main/java/cn/wildfirechat/push/ios/IOSPushType.java
Normal file
6
src/main/java/cn/wildfirechat/push/ios/IOSPushType.java
Normal file
@@ -0,0 +1,6 @@
|
||||
package cn.wildfirechat.push.ios;
|
||||
|
||||
public interface IOSPushType {
|
||||
int IOS_PUSH_TYPE_DISTRIBUTION = 0;
|
||||
int IOS_PUSH_TYPE_DEVELOPEMENT = 1;
|
||||
}
|
||||
Reference in New Issue
Block a user