APNS推送常用的框架有pushy和javaPNS两种,pushy较之javaPNS功能更为全面,但是在部署WEB项目的时候却出现了问题。pushy的运行需要制定命令行参数,需要替换虚拟机中的包,这对一个已经上线的、部署在tomcat上的javaweb项目来说不太友好,因此我最终选择了javaPNS这种更为简易的框架来实现APNS推送业务。
一、项目所需的jar包
这里才用maven的形式来依赖jar包
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.keisdom.myapns</groupId>
<artifactId>myapns</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<!--<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.51</version>
</dependency>--!>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.fernandospr</groupId>
<artifactId>javapns-jdk16</artifactId>
<version>2.2.1</version>
</dependency>
</dependencies>
</project>
第一个被注释掉的包会产生一些误区,有些教程里面会导入这个包,在一般的程序中运行也不会出现问题。但是如果tomcat设置的最大空间没有那么大,或者刚好达到临界值了,就会出现栈溢出的问题。原因在于bcprov-jdk15on的包和javapns-jdk16的包互相的引用,导致循环引用包,最终会导致栈溢出的问题,只需要把bcprov-jdk15on的包给去掉就行了,javapns-jdk16已经依赖了这个包,就不用再重复依赖了。
二、消息的定制
javapns除去一些固定的发送的消息消息之外,也可以发送自定义消息头的消息,需要调用PushNotificationPayload的Payload.addCustomDictionary(String name, String value)方法。
如果需要发送自定义的消息,需要一个类继承Payload类,可以自己加属性和重写Payload中的方法,只要规格复合ios的json字符串的格式。
三、消息的响应
如果不添加消息的响应,发送的消息就会像石沉大海一样,即不知道消息是否正确发送给了apns服务器,也不知道apns是否已经将消息转发给了ios设备。因此,需要添加响应的方法,这里不使用监听去实现消息响应,而直接调用javaPNS的方法来接收消息的响应。
由PushNotificationManager调用sendNotification(Device device, Payload payload, boolean closeAfter) 之后,会返回一个PushedNotification的对象,这个对象即可以调用相应的方法来获取响应。PushedNotification的isSuccessful()方法可以判断消息是否成功发送给了apns服务器。
2.消息是否已经由apns服务器发送给了ios设备
PushedNotification的getResponse()方法可以获得apns服务器发送消息的响应,返回一个ResponsePacket的对象,判断此对象是否为空且调用isErrorResponsePacket()方法返回true,说明消息推送失败了,这时应当作对应的处理。
package testapns;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONException;
import javapns.communication.exceptions.CommunicationException;
import javapns.communication.exceptions.KeystoreException;
import javapns.devices.Device;
import javapns.devices.implementations.basic.BasicDevice;
import javapns.notification.AppleNotificationServerBasicImpl;
import javapns.notification.PushNotificationManager;
import javapns.notification.PushNotificationPayload;
import javapns.notification.PushedNotification;
import javapns.notification.ResponsePacket;
public class PushPNS {
public static void main(String[] args) {
try {
String token ="your token";
int badge=1;
String sound="defalt";
//String url = "dev.p12";
String url = "G:\\dev.12";
String password = "123456";
PushNotificationPayload payload=new PushNotificationPayload();
payload.addAlert("您有一个视频呼叫");
payload.addBadge(badge);
payload.addCustomDictionary("remote_id", "11");
payload.addCustomDictionary("type", "video");
if(!StringUtils.isEmpty(sound)) {
payload.addSound(sound);
}
PushNotificationManager pushManager=new PushNotificationManager();
pushManager.initializeConnection(new AppleNotificationServerBasicImpl(url, password, false));
//List<PushedNotification> notifications=new ArrayList<PushedNotification>();
Device device=new BasicDevice();
device.setToken(token);
PushedNotification notification=pushManager.sendNotification(device, payload,true);
if(notification.isSuccessful()) {
ResponsePacket theErrorResponse = notification.getResponse();
if(theErrorResponse != null && theErrorResponse.isErrorResponsePacket()) {
System.out.println("APNS server cant send message to IOS");
pushManager.stopConnection();
}
pushManager.stopConnection();
}else {
pushManager.stopConnection();
System.out.println("cannot send message to APNS server");
}
} catch (JSONException e) {
e.printStackTrace();
} catch (CommunicationException e) {
e.printStackTrace();
} catch (KeystoreException e) {
e.printStackTrace();
}
}
}