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