I am having problems when doing bulk notification for iOS devices, when I do push for few devices (1-20 more less) it works without problems, but when I have to do a bulk push (3000+) it is giving me the following error:
[2017-04-27 15:12:07] ERROR (Notifications:347) - IOS: Error sending notifications - CommunicationException: javapns.communication.exceptions.CommunicationException: Communication exception: java.net.ConnectException: Connection timeout expired ͨConnection timed out) at javapns.communication.ConnectionToAppleServer.getSSLSocket(ConnectionToAppleServer.java:156) at javapns.notification.PushNotificationManager.initializeConnection(PushNotificationManager.java:106) at javapns.notification.transmission.NotificationListread.rjavapns. 215) at javapns.notification.transmission.NotificationThread.run(NotificationThread.java:199) at java.lang.Thread.run(Thread.java:745) Caused by: java.net.ConnectException: Expir → connection time → Connection timed out) at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:339) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200) at java.net.AbstractPlainSocketImpl.connect(AbstratPlainSocketImpl.connect8) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket.connect(Socket.java:576) at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:635) at sun. security.ssl.SSLSocketImpl.(SSLSocketImpl.java:423) at sun.security.ssl.SSLSocketFactoryImpl.createSocket(SSLSocketFactoryImpl.java:88) at javapns.communication.ConnectionToAppleServer.getSSLSocket(ConnectionToAppleServer.java:153) ... 4 morenet.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket (Socket.java:576) at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:635) at sun.security.ssl.SSLSocketImpl.(SSLSocketImpl.java:423) at sun.security.ssl.SSLSocketFactoryImpl.createSocket (SSLSocketFactoryImpl.java:88) at javapns.communication.ConnectionToAppleServer.getSSLSocket(ConnectionToAppleServer.java:153) ... 4 morenet.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:200) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:182) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) at java.net.Socket (Socket.java:576) at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:635) at sun.security.ssl.SSLSocketImpl.(SSLSocketImpl.java:423) at sun.security.ssl.SSLSocketFactoryImpl.createSocket (SSLSocketFactoryImpl.java:88) at javapns.communication.ConnectionToAppleServer.getSSLSocket(ConnectionToAppleServer.java:153) ... 4 moreSocket.connect(Socket.java:576) at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:635) at sun.security.ssl.SSLSocketImpl.(SSLSocketImpl.java:423) at sun.security.ssl. SSLSocketFactoryImpl.createSocket(SSLSocketFactoryImpl.java:88) at javapns.communication.ConnectionToAppleServer.getSSLSocket(ConnectionToAppleServer.java:153) ... 4 moreSocket.connect(Socket.java:576) at sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:635) at sun.security.ssl.SSLSocketImpl.(SSLSocketImpl.java:423) at sun.security.ssl. SSLSocketFactoryImpl.createSocket(SSLSocketFactoryImpl.java:88) at javapns.communication.ConnectionToAppleServer.getSSLSocket(ConnectionToAppleServer.java:153) ... 4 more
The code I am using is the following:
private static void realizaEnvioIOSLista (final List<DispositivoDto> dispositivos, final String textoES, final String textoCA, final String textoEN, final String tipoNotificacion){
//El metodo de multithread payload hace return unicamente cuando todos los hilos han finalizado de poner las notificaciones.
//Como no queremos esperar a que termine ponemos el codigo en un hilo separado para que pueda continuar y no se quede colgado el WS.
Thread thread = new Thread(){
public void run(){
try {
final List<String> idsDispositivos = new ArrayList<String>();
final String keystore = XmlUtils.dirCertIOS + XmlUtils.nomCertificado;
final String password = XmlUtils.password;
final boolean production = XmlUtils.production;
//Obtenemos los ids de los dispositivos
for(DispositivoDto r : dispositivos)
idsDispositivos.add(r.getIdDispositivo());
// Creamos el payload con los campos que necesitemos
PushNotificationPayload payload = PushNotificationBigPayload.complex();
/* Customize the payload */
payload.addAlert(textoES);
// payload.addSound('default');
payload.setContentAvailable(true);
payload.addCustomDictionary("es", textoES);
payload.addCustomDictionary("en", textoCA);
payload.addCustomDictionary("ca", textoEN);
payload.addCustomDictionary("tiponotificacion", tipoNotificacion);
List<PushedNotification> notifications = new ArrayList<PushedNotification>();
if(idsDispositivos.size()<= 200){
notifications = Push.payload(payload, keystore, password, production, idsDispositivos);
// Si hay mas de 200 dispositivos creamos diferentes hilos utilizando el multithread payload
} else {
// Decidimos cuantos hilos vamos a crear y usar
int threads = 1;
if(dispositivos.size() > 200) {
threads = (int) Math.ceil(dispositivos.size()/200);
}
// empezamos los hilos, esperamos a que terminen, y se coge la lista de notificaciones
notifications = Push.payload(payload, keystore, password, production, threads, idsDispositivos);
}
//Gestion de los resultados del envio de notificaciones
int dispEliminados = 0;
int dispNotificados = 0;
for (PushedNotification notification : notifications) {
if (notification.isSuccessful()) {
dispNotificados ++;
// Apple accepta la notificacion y debe enviarla
// logNot.info("Notificacion para el dispositivo " + notification.getDevice().getToken() + " enviada correctamente.");
} else {
String invalidToken = notification.getDevice().getToken();
//obtenemos el indice del dispositivo en la lista de dispositivos
int index = idsDispositivos.indexOf(invalidToken);
//obtenemos la informacion del dispositivo a borrar
Integer usuario = dispositivos.get(index).getUsuario();
String idHardware = dispositivos.get(index).getIdHardwareDis();
//quitamos el dispositivo de nuestra BD
aBD.unregisterDispositivo(usuario, invalidToken,idHardware);
dispEliminados ++;
logNot.info("IOS: Eliminado el dispositivo: " + usuario+ " - " + idHardware + " - " + notification.getDevice().getToken());
//Encontramos mas informacion sobre el problema ocurrido
// Exception theProblem = notification.getException();
// theProblem.printStackTrace();
//If the problem was an error-response packet returned by Apple, get it
ResponsePacket theErrorResponse = notification.getResponse();
if (theErrorResponse != null){
logNot.info("IOS: " +theErrorResponse.getMessage());
}
}
}
logNot.info("IOS: Dispositivos Notificados correctamente: " + dispNotificados);
logNot.info("IOS: Dispositivos Eliminados: " +dispEliminados);
} catch (CommunicationException e) {
logNot.error("IOS: Error en envio notificaciones - CommunicationException: ",e);
} catch (KeystoreException e) {
logNot.error("IOS: Error en envio notificaciones - KeystoreException: ",e);
} catch (JSONException e) {
logNot.error("IOS: Error en envio notificaciones - JSONException: ",e);
} catch (Exception e) {
logNot.error("IOS: Error en envio notificaciones",e);
}
}
};
thread.start();
}
I am doing something wrong? What is the maximum number of devices and connections to the Apple server that can be made? Any help is welcome.
I have found the solution to my problem, the code works fine, after talking with the system administrators we have been able to see that it was a server configuration problem, since according to this link from apple to be able to send notifications you must have note the following:
So that:
Also:
So everything has been resolved by configuring the firewall to allow these connections. I hope it helps someone.