概述
PushedNotification,该类用于获取推送消息结果信息。
所有属性如下:
private Payload payload;消息体
private Device device;目标设备
private ResponsePacket response;推送返回response信息
private int identifier;推送返回信息唯一标识 –好像没啥用
private long expiry;失效时间
private int transmissionAttempts;推送次数
private boolean transmissionCompleted;是否推送操作完成
private Exception exception;异常
构造函数和set/get方法 不再一一说
protected void setResponse(ResponsePacket response) {
this.response = response;如果异常为空 就根绝response获取一个异常 如果异常中状态为0表示推送成功没有发生异常
if (response != null && exception == null) exception = new ErrorResponsePacketReceivedException(response);
}
是否推送成功
public boolean isSuccessful() {
if (!transmissionCompleted) return false;推送操作未完成
if (response == null) return true;返回response为null表示为完成
if (!response.isValidErrorMessage()) return true;
return false;
}
public static List<PushedNotification> findSuccessfulNotifications(List<PushedNotification> notifications) {
List<PushedNotification> filteredList = new Vector<PushedNotification>();
for (PushedNotification notification : notifications) {
if (notification.isSuccessful()) filteredList.add(notification);获取成功的
}
return filteredList;
}
public static List<PushedNotification> findFailedNotifications(List<PushedNotification> notifications) {
List<PushedNotification> filteredList = new Vector<PushedNotification>();
for (PushedNotification notification : notifications) {
if (!notification.isSuccessful()) {获取失败的
filteredList.add(notification);
}
}
return filteredList;
}
public class PushedNotifications extends Vector<PushedNotification> implements List<PushedNotification> ;推送完成信息集合类,这个类也就是PushedNotification的集合,其主要方法是验证集合大小和推送成功失败的区分。
PushNotificationManager是推送的管理类,这个类用于启动连接服务器,执行推送操作。
private static int TESTS_SERIAL_NUMBER = 1;用于构造debug alert内容
private int sslSocketTimeout = 30 * 1000; 连接超时时间
static final Logger logger = Logger.getLogger(PushNotificationManager.class);日志
private static final int DEFAULT_RETRIES = 3;默认推送次数
private static final int SEQUENTIAL_IDENTIFIER = -1;推送消息返回信息唯一标识,默认为-1
private static boolean useEnhancedNotificationFormat = true;使用推送返回消息校验
private static boolean heavyDebugMode = false;是否debug
private ConnectionToAppleServer connectionToAppleServer;连接到服务器
private SSLSocket socket;安全连接socket
private int retryAttempts = DEFAULT_RETRIES;默认推送次数
private int nextMessageIdentifier = 1;推送消息返回信息唯一标识,如果是-1那么就是用这个自增数字
private boolean trustAllServerCertificates = true;信任所有的服务器证书
/* The DeviceFactory to use with this PushNotificationManager */
@Deprecated
private DeviceFactory deviceFactory;设备工厂 已经不个推荐
private LinkedHashMap<Integer, PushedNotification> pushedNotifications = new LinkedHashMap<Integer, PushedNotification>();推送返回消息集合
set/get方法和构造函数不再说
初始化连接
public void initializeConnection(AppleNotificationServer server) throws CommunicationException, KeystoreException {
try {
this.connectionToAppleServer = new ConnectionToNotificationServer(server);
this.socket = connectionToAppleServer.getSSLSocket();
if (heavyDebugMode) {//日志信息
dumpCertificateChainDescription();
}
logger.debug(“Initialized Connection to Host: [” + server.getNotificationServerHost() + “] Port: [” + server.getNotificationServerPort() + “]: ” + socket);
} catch (KeystoreException e) {
throw e;
} catch (CommunicationException e) {
throw e;
} catch (Exception e) {
throw new CommunicationException(“Error creating connection with Apple server”, e);
}
}
//使用已有服务器信息连接服务器,用于重连服务器发送发送失败的推送消息
public void initializePreviousConnection() throws CommunicationException, KeystoreException {
initializeConnection((AppleNotificationServer) this.connectionToAppleServer.getServer());
}
//重连服务器
public void restartConnection(AppleNotificationServer server) throws CommunicationException, KeystoreException {
stopConnection();
initializeConnection(server);
}
//重连连接帮助类配置的服务器
private void restartPreviousConnection() throws CommunicationException, KeystoreException {
try {
logger.debug(“Closing connection to restart previous one”);
this.socket.close();
} catch (Exception e) {
/* Do not complain if connection is already closed… */
}
initializePreviousConnection();
}
//停止连接
public void stopConnection() throws CommunicationException, KeystoreException {
processedFailedNotifications();
try {
logger.debug(“Closing connection”);
this.socket.close();
} catch (Exception e) {
/* Do not complain if connection is already closed… */
}
}
//停止服务器连接前查询是否有发送失败的信息,如果有重连并重新推送
private int processedFailedNotifications() throws CommunicationException, KeystoreException {
if (useEnhancedNotificationFormat) {//使用校验
logger.debug(“Reading responses”);
int responsesReceived = ResponsePacketReader.processResponses(this);//接收到的response的数量
while (responsesReceived > 0) {
PushedNotification skippedNotification = null;
List<PushedNotification> notificationsToResend = new ArrayList<PushedNotification>();
boolean foundFirstFail = false;
for (PushedNotification notification : pushedNotifications.values()) {
if (foundFirstFail || !notification.isSuccessful())
if (foundFirstFail) notificationsToResend.add(notification);//一个推送失败后,那么它后边的也都是失败,这个跳过,后边的继续,如果这组推送中有两个失败,那么就不再推送,所以注意清空失效token
else {
foundFirstFail = true;
skippedNotification = notification;
}
}
}
pushedNotifications.clear();
int toResend = notificationsToResend.size();
logger.debug(“Found ” + toResend + ” notifications that must be re-sent”);
if (toResend > 0) {
logger.debug(“Restarting connection to resend notifications”);
restartPreviousConnection();
for (PushedNotification pushedNotification : notificationsToResend) {
sendNotification(pushedNotification, false);
}
}
int remaining = responsesReceived = ResponsePacketReader.processResponses(this);//重发过后剩余的
if (remaining == 0) {
logger.debug(“No notifications remaining to be resent”);
return 0;
}
}
return responsesReceived;//这个数据也没啥用 很坑爹
} else {
logger.debug(“Not reading responses because using simple notification format”);
return 0;
}
}
//构造推送消息
private byte[] getMessage(String deviceToken, Payload payload, int identifier, PushedNotification message) throws IOException, Exception {
logger.debug(“Building Raw message from deviceToken and payload”);
/* To test with a corrupted or invalid token, uncomment following line*/
//deviceToken = deviceToken.substring(0,10);
// First convert the deviceToken (in hexa form) to a binary format
byte[] deviceTokenAsBytes = new byte[deviceToken.length() / 2];
deviceToken = deviceToken.toUpperCase();
int j = 0;
try {
for (int i = 0; i < deviceToken.length(); i += 2) {
String t = deviceToken.substring(i, i + 2);
int tmp = Integer.parseInt(t, 16);
deviceTokenAsBytes[j++] = (byte) tmp;
}
} catch (NumberFormatException e1) {
throw new InvalidDeviceTokenFormatException(deviceToken, e1.getMessage());
}
preconfigurePayload(payload, identifier, deviceToken);
// Create the ByteArrayOutputStream which will contain the raw interface
byte[] payloadAsBytes = payload.getPayloadAsBytes();
int size = (Byte.SIZE / Byte.SIZE) + (Character.SIZE / Byte.SIZE) + deviceTokenAsBytes.length + (Character.SIZE / Byte.SIZE) + payloadAsBytes.length;
ByteArrayOutputStream bao = new ByteArrayOutputStream(size);
// Write command to ByteArrayOutputStream
// 0 = simple
// 1 = enhanced
if (useEnhancedNotificationFormat) {
byte b = 1;
bao.write(b);
} else {
byte b = 0;
bao.write(b);
}
if (useEnhancedNotificationFormat) {
// 4 bytes identifier (which will match any error packet received later on)
bao.write(intTo4ByteArray(identifier));
message.setIdentifier(identifier);
// 4 bytes
int requestedExpiry = payload.getExpiry();
if (requestedExpiry <= 0) {
bao.write(intTo4ByteArray(requestedExpiry));
message.setExpiry(0);
} else {
long ctime = System.currentTimeMillis();
long ttl = requestedExpiry * 1000; // time-to-live in milliseconds
Long expiryDateInSeconds = ((ctime + ttl) / 1000L);
bao.write(intTo4ByteArray(expiryDateInSeconds.intValue()));
message.setExpiry(ctime + ttl);
}
}
// Write the TokenLength as a 16bits unsigned int, in big endian
int tl = deviceTokenAsBytes.length;
bao.write(intTo2ByteArray(tl));
// Write the Token in bytes
bao.write(deviceTokenAsBytes);
// Write the PayloadLength as a 16bits unsigned int, in big endian
int pl = payloadAsBytes.length;
bao.write(intTo2ByteArray(pl));
// Finally write the Payload
bao.write(payloadAsBytes);
bao.flush();
byte[] bytes = bao.toByteArray();
if (heavyDebugMode) {
try {
FileOutputStream outf = new FileOutputStream(“apns-message.bytes”);
outf.write(bytes);
outf.close();
} catch (Exception e) {
}
}
logger.debug(“Built raw message ID ” + identifier + ” of total length ” + bytes.length);
return bytes;
}
private static final byte[] intTo2ByteArray(int value) {
int s1 = (value & 0xFF00) >> 8;
int s2 = value & 0xFF;
return new byte[] { (byte) s1, (byte) s2 };
}
private int newMessageIdentifier() {
int id = nextMessageIdentifier;
nextMessageIdentifier++;
return id;
}
//根据配置初始化一个消息信息
private void preconfigurePayload(Payload payload, int identifier, String deviceToken) {
try {
int config = payload.getPreSendConfiguration();
if (payload instanceof PushNotificationPayload) {
PushNotificationPayload pnpayload = (PushNotificationPayload) payload;
if (config == 1) {
pnpayload.getPayload().remove(“alert”);
pnpayload.addAlert(buildDebugAlert(payload, identifier, deviceToken));
}
}
} catch (Exception e) {
}
}
//创建debug消息信息
private String buildDebugAlert(Payload payload, int identifier, String deviceToken) {
StringBuilder alert = new StringBuilder();
alert.append(“JAVAPNS DEBUG ALERT ” + (TESTS_SERIAL_NUMBER++) + “n”);
/* Current date & time */
alert.append(new SimpleDateFormat(“yyyy/MM/dd HH:mm:ss”).format(System.currentTimeMillis()) + “n”);
/* Selected Apple server */
alert.append(this.connectionToAppleServer.getServerHost() + “n”);
/* Device token (shortened), Identifier and expiry */
int l = useEnhancedNotificationFormat ? 4 : 8;
alert.append(“” + deviceToken.substring(0, l) + “�” + deviceToken.substring(64 – l, 64) + (useEnhancedNotificationFormat ? ” [Id:” + identifier + “] ” + (payload.getExpiry() <= 0 ? “No-store” : “Exp:T+” + payload.getExpiry()) : “”) + “n”);
/* Format & encoding */
alert.append((useEnhancedNotificationFormat ? “Enhanced” : “Simple”) + ” format / ” + payload.getCharacterEncoding() + “” + “”);
return alert.toString();
}
推送方法
private void sendNotification(PushedNotification notification, boolean closeAfter) throws CommunicationException {
try {
Device device = notification.getDevice();
Payload payload = notification.getPayload();
try {
payload.verifyPayloadIsNotEmpty();
} catch (IllegalArgumentException e) {
throw new PayloadIsEmptyException();
} catch (Exception e) {
}
if (notification.getIdentifier() <= 0) notification.setIdentifier(newMessageIdentifier());
if (!pushedNotifications.containsKey(notification.getIdentifier())) pushedNotifications.put(notification.getIdentifier(), notification);放入集合,
int identifier = notification.getIdentifier();
以上为配置notification对象信息
String token = device.getToken();
// even though the BasicDevice constructor validates the token, we revalidate it in case we were passed another implementation of Device
BasicDevice.validateTokenFormat(token);
byte[] bytes = getMessage(token, payload, identifier, notification);
/* Special simulation mode to skip actual streaming of message */
boolean simulationMode = payload.getExpiry() == 919191;如果是仿真模式
boolean success = false;
BufferedReader in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
int socketTimeout = getSslSocketTimeout();
if (socketTimeout > 0) this.socket.setSoTimeout(socketTimeout);
notification.setTransmissionAttempts(0);
// Keep trying until we have a success
while (!success) {
try {
logger.debug(“Attempting to send notification: ” + payload.toString() + “”);
logger.debug(” to device: ” + token + “”);
notification.addTransmissionAttempt();
boolean streamConfirmed = false;
try {
if (!simulationMode) {
this.socket.getOutputStream().write(bytes);
streamConfirmed = true;
} else {
logger.debug(“* Simulation only: would have streamed ” + bytes.length + “-bytes message now..”);
}
} catch (Exception e) {
if (e != null) {
if (e.toString().contains(“certificate_unknown”)) {
throw new InvalidCertificateChainException(e.getMessage());
}
}
throw e;
}
logger.debug(“Flushing”);
this.socket.getOutputStream().flush();
if (streamConfirmed) logger.debug(“At this point, the entire ” + bytes.length + “-bytes message has been streamed out successfully through the SSL connection”);
success = true;
logger.debug(“Notification sent on ” + notification.getLatestTransmissionAttempt());
notification.setTransmissionCompleted(true);
} catch (IOException e) {
// throw exception if we surpassed the valid number of retry attempts
if (notification.getTransmissionAttempts() >= retryAttempts) {
logger.error(“Attempt to send Notification failed and beyond the maximum number of attempts permitted”);
notification.setTransmissionCompleted(false);
notification.setException(e);
logger.error(“Delivery error”, e);
throw e;
} else {
logger.info(“Attempt failed (” + e.getMessage() + “)… trying again”);
//Try again
try {
this.socket.close();
} catch (Exception e2) {
// do nothing
}
this.socket = connectionToAppleServer.getSSLSocket();
if (socketTimeout > 0) this.socket.setSoTimeout(socketTimeout);
}
}
}
} catch (CommunicationException e) {
throw e;
} catch (Exception ex) {
notification.setException(ex);
logger.error(“Delivery error: ” + ex);
try {
if (closeAfter) {
logger.error(“Closing connection after error”);
stopConnection();
}
} catch (Exception e) {
}
}
}
//给单独设备推送一个消息
public PushedNotification sendNotification(Device device, Payload payload) throws CommunicationException {
return sendNotification(device, payload, true);
}
//给指定设备组发送推送,并关闭连接
public PushedNotifications sendNotifications(Payload payload, List<Device> devices) throws CommunicationException, KeystoreException {
PushedNotifications notifications = new PushedNotifications();
for (Device device : devices)
notifications.add(sendNotification(device, payload, false, SEQUENTIAL_IDENTIFIER));
stopConnection();
return notifications;
}
//给指定设备组推送 并在推送完毕后关闭连接
public PushedNotifications sendNotifications(Payload payload, Device… devices) throws CommunicationException, KeystoreException {
PushedNotifications notifications = new PushedNotifications();
for (Device device : devices)
notifications.add(sendNotification(device, payload, false, SEQUENTIAL_IDENTIFIER));
stopConnection();
return notifications;
}
//给指定的设备发送推送
public PushedNotification sendNotification(Device device, Payload payload, boolean closeAfter) throws CommunicationException {
return sendNotification(device, payload, closeAfter, SEQUENTIAL_IDENTIFIER);
}
//给指定的用户发送推送
public PushedNotification sendNotification(Device device, Payload payload, int identifier) throws CommunicationException {
return sendNotification(device, payload, false, identifier);
}
//给指定的设备发送推送
public PushedNotification sendNotification(Device device, Payload payload, boolean closeAfter, int identifier) throws CommunicationException {
PushedNotification pushedNotification = new PushedNotification(device, payload, identifier);
sendNotification(pushedNotification, closeAfter);
return pushedNotification;
}
最后
以上就是高挑夕阳为你收集整理的iOS推送javaPNS源码解析七,推送信息类的全部内容,希望文章能够帮你解决iOS推送javaPNS源码解析七,推送信息类所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复