This commit is contained in:
93
src-plugin/com/wentch/redkale/service/apns/ApnsMessage.java
Normal file
93
src-plugin/com/wentch/redkale/service/apns/ApnsMessage.java
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.wentch.redkale.service.apns;
|
||||||
|
|
||||||
|
import com.wentch.redkale.convert.json.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class ApnsMessage {
|
||||||
|
|
||||||
|
public static final int PRIORITY_IMMEDIATELY = 10;
|
||||||
|
|
||||||
|
public static final int PRIORITY_A_TIME = 5;
|
||||||
|
|
||||||
|
private ApnsPayload payload;
|
||||||
|
|
||||||
|
private int expiredate;
|
||||||
|
|
||||||
|
private int priority = PRIORITY_IMMEDIATELY;
|
||||||
|
|
||||||
|
private int identifier;
|
||||||
|
|
||||||
|
private String token;
|
||||||
|
|
||||||
|
public ApnsMessage() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApnsMessage(String token, ApnsPayload payload) {
|
||||||
|
this(token, payload, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApnsMessage(String token, ApnsPayload payload, int expiredate) {
|
||||||
|
this(token, payload, expiredate, PRIORITY_IMMEDIATELY);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApnsMessage(String token, ApnsPayload payload, int expiredate, int priority) {
|
||||||
|
this.token = token;
|
||||||
|
this.payload = payload;
|
||||||
|
this.expiredate = expiredate;
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getToken() {
|
||||||
|
return token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToken(String token) {
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getExpiredate() {
|
||||||
|
return expiredate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpiredate(int expiredate) {
|
||||||
|
this.expiredate = expiredate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPriority() {
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPriority(int priority) {
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApnsPayload getPayload() {
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPayload(ApnsPayload payload) {
|
||||||
|
this.payload = payload;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getIdentifier() {
|
||||||
|
return identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setIdentifier(int identifier) {
|
||||||
|
this.identifier = identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return JsonFactory.root().getConvert().convertTo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
247
src-plugin/com/wentch/redkale/service/apns/ApnsPayload.java
Normal file
247
src-plugin/com/wentch/redkale/service/apns/ApnsPayload.java
Normal file
@@ -0,0 +1,247 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.wentch.redkale.service.apns;
|
||||||
|
|
||||||
|
import com.wentch.redkale.convert.json.*;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.regex.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class ApnsPayload {
|
||||||
|
|
||||||
|
private static final Pattern regex = Pattern.compile("\"");
|
||||||
|
|
||||||
|
//----------------------- alert ---------------------------------
|
||||||
|
private String alertTitle;
|
||||||
|
|
||||||
|
private String alertBody;
|
||||||
|
|
||||||
|
private String alertTitleLocKey;
|
||||||
|
|
||||||
|
private String[] alertTitleLocArgs;
|
||||||
|
|
||||||
|
private String alertActionLocKey;
|
||||||
|
|
||||||
|
private String alertLocKey;
|
||||||
|
|
||||||
|
private String[] alertLocArgs;
|
||||||
|
|
||||||
|
private String alertLaunchImage;
|
||||||
|
|
||||||
|
//--------------------------------------------------------
|
||||||
|
private int contentAvailable;
|
||||||
|
|
||||||
|
private String alert;
|
||||||
|
|
||||||
|
private int badge;
|
||||||
|
|
||||||
|
private String sound;
|
||||||
|
|
||||||
|
private final Map<String, Object> attributes = new HashMap<>();
|
||||||
|
|
||||||
|
public ApnsPayload() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApnsPayload(String alert, int badge) {
|
||||||
|
this.alert = alert;
|
||||||
|
this.badge = badge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ApnsPayload(String title, String body, int badge) {
|
||||||
|
this.alertTitle = title;
|
||||||
|
this.alertBody = body;
|
||||||
|
this.badge = badge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void putAttribute(String name, Object value) {
|
||||||
|
attributes.put(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAttribute(String name) {
|
||||||
|
attributes.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> T getAttribute(String name) {
|
||||||
|
return (T) attributes.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> getAttributes() {
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttributes(Map<String, Object> map) {
|
||||||
|
if (map != null) attributes.putAll(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
StringBuilder alertsb = new StringBuilder();
|
||||||
|
if (alert != null) {
|
||||||
|
alertsb.append('"').append(regex.matcher(alert).replaceAll("\\\"")).append('"');
|
||||||
|
} else {
|
||||||
|
alertsb.append('{');
|
||||||
|
if (alertTitle != null) {
|
||||||
|
if (alertsb.length() > 1) alertsb.append(',');
|
||||||
|
alertsb.append("\"title\":\"").append(regex.matcher(alertTitle).replaceAll("\\\"")).append('"');
|
||||||
|
}
|
||||||
|
if (alertBody != null) {
|
||||||
|
if (alertsb.length() > 1) alertsb.append(',');
|
||||||
|
alertsb.append("\"body\":\"").append(regex.matcher(alertBody).replaceAll("\\\"")).append('"');
|
||||||
|
}
|
||||||
|
if (alertTitleLocKey != null) {
|
||||||
|
if (alertsb.length() > 1) alertsb.append(',');
|
||||||
|
alertsb.append("\"title-loc-key\":\"").append(regex.matcher(alertTitleLocKey).replaceAll("\\\"")).append('"');
|
||||||
|
}
|
||||||
|
if (alertTitleLocArgs != null && alertTitleLocArgs.length > 0) {
|
||||||
|
if (alertsb.length() > 1) alertsb.append(',');
|
||||||
|
alertsb.append("\"title-loc-args\":[");
|
||||||
|
boolean first = true;
|
||||||
|
for (String str : alertTitleLocArgs) {
|
||||||
|
if (!first) alertsb.append(',');
|
||||||
|
alertsb.append('"').append(regex.matcher(str).replaceAll("\\\"")).append('"');
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
alertsb.append(']');
|
||||||
|
}
|
||||||
|
if (alertActionLocKey != null) {
|
||||||
|
if (alertsb.length() > 1) alertsb.append(',');
|
||||||
|
alertsb.append("\"action-loc-key\":\"").append(regex.matcher(alertActionLocKey).replaceAll("\\\"")).append('"');
|
||||||
|
}
|
||||||
|
if (alertLocKey != null) {
|
||||||
|
if (alertsb.length() > 1) alertsb.append(',');
|
||||||
|
alertsb.append("\"loc-key\":\"").append(regex.matcher(alertLocKey).replaceAll("\\\"")).append('"');
|
||||||
|
}
|
||||||
|
if (alertLocArgs != null && alertLocArgs.length > 0) {
|
||||||
|
if (alertsb.length() > 1) alertsb.append(',');
|
||||||
|
alertsb.append("\"loc-args\":[");
|
||||||
|
boolean first = true;
|
||||||
|
for (String str : alertLocArgs) {
|
||||||
|
if (!first) alertsb.append(',');
|
||||||
|
alertsb.append('"').append(regex.matcher(str).replaceAll("\\\"")).append('"');
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
alertsb.append(']');
|
||||||
|
}
|
||||||
|
if (alertLaunchImage != null) {
|
||||||
|
if (alertsb.length() > 1) alertsb.append(',');
|
||||||
|
alertsb.append("\"launch-image\":\"").append(regex.matcher(alertLaunchImage).replaceAll("\\\"")).append('"');
|
||||||
|
}
|
||||||
|
alertsb.append('}');
|
||||||
|
}
|
||||||
|
final StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append("{\"aps\":{\"alert\":").append(alertsb);
|
||||||
|
if (badge > 0) sb.append(",\"badge\":").append(badge);
|
||||||
|
if (contentAvailable > 0) sb.append(",\"content-available\":").append(contentAvailable);
|
||||||
|
if (sound != null) sb.append(",\"sound\":\"").append(sound).append('"');
|
||||||
|
sb.append("}");
|
||||||
|
if (attributes.isEmpty()) {
|
||||||
|
sb.append('}');
|
||||||
|
} else {
|
||||||
|
sb.append(',').append(JsonFactory.root().getConvert().convertTo(attributes).substring(1));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlertTitle() {
|
||||||
|
return alertTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlertTitle(String alertTitle) {
|
||||||
|
this.alertTitle = alertTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlertBody() {
|
||||||
|
return alertBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlertBody(String alertBody) {
|
||||||
|
this.alertBody = alertBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlertTitleLocKey() {
|
||||||
|
return alertTitleLocKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlertTitleLocKey(String alertTitleLocKey) {
|
||||||
|
this.alertTitleLocKey = alertTitleLocKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getAlertTitleLocArgs() {
|
||||||
|
return alertTitleLocArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlertTitleLocArgs(String[] alertTitleLocArgs) {
|
||||||
|
this.alertTitleLocArgs = alertTitleLocArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlertActionLocKey() {
|
||||||
|
return alertActionLocKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlertActionLocKey(String alertActionLocKey) {
|
||||||
|
this.alertActionLocKey = alertActionLocKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlertLocKey() {
|
||||||
|
return alertLocKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlertLocKey(String alertLocKey) {
|
||||||
|
this.alertLocKey = alertLocKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getAlertLocArgs() {
|
||||||
|
return alertLocArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlertLocArgs(String[] alertLocArgs) {
|
||||||
|
this.alertLocArgs = alertLocArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlertLaunchImage() {
|
||||||
|
return alertLaunchImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlertLaunchImage(String alertLaunchImage) {
|
||||||
|
this.alertLaunchImage = alertLaunchImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getContentAvailable() {
|
||||||
|
return contentAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContentAvailable(int contentAvailable) {
|
||||||
|
this.contentAvailable = contentAvailable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAlert() {
|
||||||
|
return alert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAlert(String alert) {
|
||||||
|
this.alert = alert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBadge() {
|
||||||
|
return badge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBadge(int badge) {
|
||||||
|
this.badge = badge;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSound() {
|
||||||
|
return sound;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSound(String sound) {
|
||||||
|
this.sound = sound;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
147
src-plugin/com/wentch/redkale/service/apns/ApnsService.java
Normal file
147
src-plugin/com/wentch/redkale/service/apns/ApnsService.java
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package com.wentch.redkale.service.apns;
|
||||||
|
|
||||||
|
import com.wentch.redkale.convert.json.*;
|
||||||
|
import com.wentch.redkale.service.*;
|
||||||
|
import com.wentch.redkale.util.*;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.nio.*;
|
||||||
|
import java.nio.channels.*;
|
||||||
|
import java.nio.charset.*;
|
||||||
|
import java.security.*;
|
||||||
|
import java.util.logging.*;
|
||||||
|
import javax.annotation.*;
|
||||||
|
import javax.net.ssl.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
public class ApnsService implements Service {
|
||||||
|
|
||||||
|
private static final Charset UTF8 = Charset.forName("UTF-8");
|
||||||
|
|
||||||
|
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
protected JsonConvert convert;
|
||||||
|
|
||||||
|
@Resource(name = "property.apns.certpwd")
|
||||||
|
protected String apnscertpwd = "1"; //证书的密码
|
||||||
|
|
||||||
|
@Resource(name = "property.apns.certpath") //用来加载证书用
|
||||||
|
protected String apnscertpath = "apnspushdev_cert.p12";
|
||||||
|
|
||||||
|
@Resource(name = "property.apns.pushaddr") //
|
||||||
|
protected String apnspushaddr = "gateway.sandbox.push.apple.com";
|
||||||
|
|
||||||
|
@Resource(name = "property.apns.pushport") //
|
||||||
|
protected int apnspushport = 2195;
|
||||||
|
|
||||||
|
@Resource(name = "property.apns.buffersize") //
|
||||||
|
protected int apnsbuffersize = 4096;
|
||||||
|
|
||||||
|
private final Object socketlock = new Object();
|
||||||
|
|
||||||
|
private SSLSocketFactory sslFactory;
|
||||||
|
|
||||||
|
private Socket pushSocket;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(AnyValue conf) {
|
||||||
|
try {
|
||||||
|
final String path = "/" + this.getClass().getPackage().getName().replace('.', '/') + "/" + apnscertpath;
|
||||||
|
KeyStore ks = KeyStore.getInstance("PKCS12");
|
||||||
|
InputStream in = ApnsService.class.getResourceAsStream(path);
|
||||||
|
ks.load(in, apnscertpwd.toCharArray());
|
||||||
|
in.close();
|
||||||
|
KeyManagerFactory kf = KeyManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
|
kf.init(ks, apnscertpwd.toCharArray());
|
||||||
|
|
||||||
|
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
|
||||||
|
tmf.init((KeyStore) null);
|
||||||
|
SSLContext context = SSLContext.getInstance("TLS");
|
||||||
|
context.init(kf.getKeyManagers(), tmf.getTrustManagers(), null);
|
||||||
|
this.sslFactory = context.getSocketFactory();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, this.getClass().getSimpleName() + " init SSLContext error", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy(AnyValue conf) {
|
||||||
|
try {
|
||||||
|
if (pushSocket != null) pushSocket.close();
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Socket getPushSocket() throws IOException {
|
||||||
|
if (this.sslFactory == null) return null;
|
||||||
|
if (pushSocket == null || pushSocket.isClosed()) {
|
||||||
|
synchronized (socketlock) {
|
||||||
|
if (pushSocket == null || pushSocket.isClosed()) {
|
||||||
|
pushSocket = sslFactory.createSocket(apnspushaddr, apnspushport);
|
||||||
|
pushSocket.setTcpNoDelay(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pushSocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void pushApnsMessage(ApnsMessage message) throws IOException {
|
||||||
|
final byte[] tokens = Utility.hexToBin(message.getToken().replaceAll("\\s+", ""));
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(apnsbuffersize);
|
||||||
|
buffer.put((byte) 2); //固定命令号
|
||||||
|
buffer.putInt(0); //下面数据的长度
|
||||||
|
|
||||||
|
buffer.put((byte) 1); //token
|
||||||
|
buffer.putShort((short) tokens.length);
|
||||||
|
buffer.put(tokens);
|
||||||
|
|
||||||
|
buffer.put((byte) 2); //payload
|
||||||
|
final byte[] payload = message.getPayload().toString().getBytes(UTF8);
|
||||||
|
buffer.putShort((short) payload.length);
|
||||||
|
buffer.put(payload);
|
||||||
|
|
||||||
|
if (message.getIdentifier() > 0) {
|
||||||
|
buffer.put((byte) 3); //Notification identifier
|
||||||
|
buffer.putShort((short) 4);
|
||||||
|
buffer.putInt(message.getIdentifier());
|
||||||
|
}
|
||||||
|
if (message.getExpiredate() > 0) {
|
||||||
|
buffer.put((byte) 4); //Expiration date
|
||||||
|
buffer.putShort((short) 4);
|
||||||
|
buffer.putInt(message.getExpiredate());
|
||||||
|
}
|
||||||
|
buffer.put((byte) 5); //Priority
|
||||||
|
buffer.putShort((short) 1);
|
||||||
|
buffer.put((byte) message.getPriority());
|
||||||
|
|
||||||
|
final int pos = buffer.position();
|
||||||
|
buffer.position(1);
|
||||||
|
buffer.putInt(pos - 5);
|
||||||
|
buffer.position(pos);
|
||||||
|
buffer.flip();
|
||||||
|
|
||||||
|
Socket socket = getPushSocket();
|
||||||
|
Channels.newChannel(socket.getOutputStream()).write(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
ApnsService service = new ApnsService();
|
||||||
|
service.convert = JsonFactory.root().getConvert();
|
||||||
|
service.init(null);
|
||||||
|
|
||||||
|
final String token = "01727b19 b9f8abf4 0891e31d 3446479d a43902e1 819edc44 a073d951 b8b7db90";
|
||||||
|
ApnsPayload payload = new ApnsPayload("您有新的消息", "这是消息内容", 1);
|
||||||
|
System.out.println(payload);
|
||||||
|
service.pushApnsMessage(new ApnsMessage(token, payload));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user