Search code examples
javaiospush-notificationpayload

Problems sending bulk iOS notifications


I'm having problems sending bulk notifications for iOS devices, when I send out a few devices (1-20 more or less) it works without problems, but when I have to send a bulk send (3000+) it is giving me the following error:

[2017-04-27 15:12:07] ERROR (Notificaciones:347) - IOS: Error en envio notificaciones - CommunicationException: javapns.communication.exceptions.CommunicationException: Communication exception: java.net.ConnectException: Expir󠥬 tiempo de conexi󮠨Connection timed out) at javapns.communication.ConnectionToAppleServer.getSSLSocket(ConnectionToAppleServer.java:156) at javapns.notification.PushNotificationManager.initializeConnection(PushNotificationManager.java:106) at javapns.notification.transmission.NotificationThread.runList(NotificationThread.java:215) at javapns.notification.transmission.NotificationThread.run(NotificationThread.java:199) at java.lang.Thread.run(Thread.java:745) Caused by: java.net.ConnectException: Expir󠥬 tiempo de conexi󮠨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(AbstractPlainSocketImpl.java:182) 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 more

My code is the following:

private static  void realizaEnvioIOSLista (final List<DispositivoDto> dispositivos, final String textoES, final String textoCA, final String textoEN, final String tipoNotificacion){       

        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());                  

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

                    } else {
                        int threads = 1;

                        if(dispositivos.size() > 200) {
                            threads = (int) Math.ceil(dispositivos.size()/200);
                        }

                        notifications = Push.payload(payload, keystore, password, production, threads, idsDispositivos);  
                    }

                    int dispEliminados = 0;
                    int dispNotificados = 0;

                    for (PushedNotification notification : notifications) {
                        if (notification.isSuccessful()) {
                            dispNotificados ++;
                        } else {
                            String invalidToken = notification.getDevice().getToken();

                            int index = idsDispositivos.indexOf(invalidToken);

                            Integer usuario = dispositivos.get(index).getUsuario();
                            String idHardware = dispositivos.get(index).getIdHardwareDis();

                            aBD.unregisterDispositivo(usuario, invalidToken,idHardware);
                            dispEliminados ++;

        //                  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();
    }

something wrong? What is the maximum number of devices and connections to the Apple server can be made? Any help is welcome.


Solution

  • I found the solution to my problem, the code works fine, after talking with the system administrators we could see that it was a problem of configuration of the servers, since according to this link of apple to be able to send of notifications, the following must be taken into consideration:

    To use Apple Push Notification service (APNs), your Mac and iOS clients need a direct and persistent connection to Apple's servers.

    So that:

    If you use Wi-Fi behind a firewall, or private Access Point Name for cellular data, connect to specific ports. You need a direct, unproxied connection to the APNs servers on these ports:

    • TCP port 5223 to communicate with APNs.
    • TCP port 2195 to send notifications to APNs.
    • TCP port 2196 for the APNs feedback service.
    • TCP port 443 is required during device activation, and afterwards for fallback (on Wi-Fi only) if devices can't reach APNs on port 5223.

    Moreover:

    The APNs servers use load balancing, so your devices don't always connect to the same public IP address for notifications. It's best to let your device access these ports on the entire 17.0.0.0/8 address block, which is assigned to Apple.

    So everything has been resolved by configuring the firewall, by the system administrators, to allow these connections. I hope it helps someone.