本文应该有很多不对的地方,仅供参考 :)
一不小心,把sandbox和production的device token都放到同一个db table里了,大件事!因为sandbox的device token对于production是invalid的,反之亦然。
具体代码是:
String certFilePath="/Users/issliao/tomson/certs/dev/dev_cert.p12"; String certPassword="xxx"; boolean isSendingProductionNotification=false; try { //create payload PushNotificationPayload payLoad= new PushNotificationPayload(); payLoad.addAlert("test"); payLoad.addSound("default"); //add device token list List<Device> devices = new ArrayList<Device>(); devices.add(new BasicDevice("12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde1112")); //wrong token devices.add(new BasicDevice("02a2fca6e3ec1ea62aa4b6a344fb9ad7f31f491b7099c0ddf7761cea6c563980")); //iphone pro devices.add(new BasicDevice("43fcc3cff12965bc45bf842bf9166fa60e8240c575d0aeb0bf395fb7ff86b466")); //ipod dev devices.add(new BasicDevice("e23411a04b4851c36efbdcd3f260df3acc1820b5ca6a4270ecb43b654cb8c022")); //ipod pro devices.add(new BasicDevice("12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde1111")); //wrong token /** * !!注意: 如果使用"sendNotifications" method一次过把notification send to all devices, 如果devices太多的话,会出现问题: 对于一些invalid device token也会显示send successful * 举个例子,你把50个"12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde1112"添加到device list变量里试试,output会有以一些显示send successful * * 因此,解决方法就是每个由PushNotificationManager创建的connection只发送一个notificaiton给一个device token!下面的代码就是每个connection只发送notification给一个device! */ for (Device device: devices){ PushNotificationManager pushManager=new PushNotificationManager(); /** * sandbox apns server: gateway.sandbox.push.apple.com port 2195 * production apns server: gateway.push.apple.com port 2195 */ //connect to apns //3rd param: false = sandbox true = production pushManager=new PushNotificationManager(); pushManager.initializeConnection(new AppleNotificationServerBasicImpl(certFilePath, certPassword, isSendingProductionNotification)); List<PushedNotification> notifications=pushManager.sendNotifications(payLoad, device); //send to only one device List<PushedNotification> failedNotifications=PushedNotification.findFailedNotifications(notifications); List<PushedNotification> successfulNotifications=PushedNotification.findSuccessfulNotifications(notifications); for (PushedNotification successfulNoticiation : successfulNotifications) { System.out.println("=====successful notification===="); System.out.println(successfulNoticiation.getDevice().getToken()); } for (PushedNotification failedNoticiation : failedNotifications) { System.out.println("=====fail notification===="); System.out.println(failedNoticiation.getDevice().getToken()); if(failedNoticiation.getException()!=null) System.out.println(failedNoticiation.getException().getMessage()); } } } catch(Exception e){ e.printStackTrace();
关于javapns (v2.2)
* send single notification
PushNotificationManager的sendNotification有问题,不管device token是否valid,返回的notification的“isSuccessful"都返回true。见下例,device token明显是错的,output依然是trueDevice device=new BasicDevice("12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde1111"); PushedNotification notification = pushManager.sendNotification(device, payLoad, true); System.out.println(notification.isSuccessful());
Device device=new BasicDevice("12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde1111"); List<PushedNotification> notifications = pushManager.sendNotifications(payLoad, device); List<PushedNotification> failedNotifications=PushedNotification.findFailedNotifications(notifications); for (PushedNotification failedNoticiation : failedNotifications) { System.out.println(failedNoticiation.getDevice().getToken()); if(failedNoticiation.getException()!=null) System.out.println(failedNoticiation.getException().getMessage()); }
* batch send notification to multiple devices
正如之前提到的,如果使用"sendNotifications" method一次过把notification send to all devices, 如果devices太多的话,会出现问题: 对于一些invalid device token也会显示send successful. (我试过一次性send 10个device没问题,send 50个就有问题)
举个例子,你把50个"12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde1112"添加到device list变量里试试,output会有以一些显示send successful. 因此,解决方法就是每个由PushNotificationManager创建的connection只发送一个notificaiton给一个device token!
不过每个connection只发送给一个device token有严重的缺点:
* apns feedback 可能没用了
* apns server可能不允许短时间频繁创建connection,可能被认为是ddos attack。
最优的是(前提是没有invalid token) 每个connection发送200条。超过200条就另建connection.
ref:
http://stackoverflow.com/questions/6819315/max-number-of-devices-to-send-to-apns-socket-sever
http://www.v2ex.com/t/23837
List<Device> devices = new ArrayList<Device>(); devices.add(new BasicDevice("12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde1111")); //wrong token devices.add(new BasicDevice("02a2fca6e3ec1ea62aa4b6a344fb9ad7f31f491b7099c0ddf7761cea6c563921")); //iphone pro devices.add(new BasicDevice("43fcc3cff12965bc45bf842bf9166fa60e8240c575d0aeb0bf395fb7ff86b421")); //ipod dev devices.add(new BasicDevice("e23411a04b4851c36efbdcd3f260df3acc1820b5ca6a4270ecb43b654cb8c021")); //ipod pro devices.add(new BasicDevice("12345abcde12345abcde12345abcde12345abcde12345abcde12345abcde1111")); //wrong token for (Device device: devices){ PushNotificationManager pushManager=new PushNotificationManager(); /** * sandbox apns server: gateway.sandbox.push.apple.com port 2195 * production apns server: gateway.push.apple.com port 2195 */ //connect to apns //3rd param: false = sandbox true = production pushManager=new PushNotificationManager(); pushManager.initializeConnection(new AppleNotificationServerBasicImpl(certFilePath, certPassword, isSendingProductionNotification)); List<PushedNotification> notifications=pushManager.sendNotifications(payLoad, device); //send to only one device List<PushedNotification> failedNotifications=PushedNotification.findFailedNotifications(notifications); List<PushedNotification> successfulNotifications=PushedNotification.findSuccessfulNotifications(notifications); for (PushedNotification successfulNoticiation : successfulNotifications) { System.out.println("=====successful notification===="); System.out.println(successfulNoticiation.getDevice().getToken()); } for (PushedNotification failedNoticiation : failedNotifications) { System.out.println("=====fail notification===="); System.out.println(failedNoticiation.getDevice().getToken()); if(failedNoticiation.getException()!=null) System.out.println(failedNoticiation.getException().getMessage()); } }
* Feedback
String certFilePath="/Users/tomson/certs/production/aps_production.p12"; String certPassword="XXXX"; boolean isSendingProductionNotification=true; try { List<Device> inactiveDevices = Push.feedback(certFilePath, certPassword, isSendingProductionNotification); for (Device inactiveDevice : inactiveDevices) { System.out.println(inactiveDevice.getToken()); } } catch (Exception e) { e.printStackTrace(); }
注意:
* feedback返回的只是那些inactive device token list。而不会包含那些你曾经send notification to invalid token的device list。
* feedback只会返回最近那次send notification的inactive token list。当你再次send notification时之前的inactive token list就会清空。
* 当你执行上述代码来get feedback后,server side就会清空inactive token list,即你再get feedback时inactive token list为empty。
举个例子:batch send一个notification给4个device tokens with production apns cert:
> device A with production token
> device A with dev token
> device B with production token,但device B已经卸载了app
> 无效的假device token。
发送notificaiton之后,执行上面的feedback代码,那么返回的inactive token list中只会包含device B production token,而不会包含假devie token and device A dev token。
* inactive device token通常是指那些安装过app又卸载了app的device。官方解释为
If a provider attempts to deliver a push notification to an application, but the application no longer exists on the device, the device reports that fact to Apple Push Notification Service. This situation often happens when the user has uninstalled the application. If a device reports failed-delivery attempts for an application, APNs needs some way to inform the provider so that it can refrain from sending notifications to that device. Doing this reduces unnecessary message overhead and improves overall system performance.
For this purpose Apple Push Notification Service includes a feedback service that APNs continually updates with a per-application list of devices for which there were failed-delivery attempts. The devices are identified by device tokens encoded in binary format. Providers should periodically query the feedback service to get the list of device tokens for their applications, each of which is identified by its topic. Then, after verifying that the application hasn’t recently been re-registered on the identified devices, a provider should stop sending notifications to these devices.