This commit is contained in:
地平线
2015-08-18 15:40:31 +08:00
parent f9ceb1afc4
commit 97cba4b524
3 changed files with 487 additions and 0 deletions

View 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);
}
}

View 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;
}
}

View 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));
}
}