批量发送 iOS 通知时出现问题

Problems sending bulk iOS notifications

我在发送 iOS 设备的批量通知时遇到问题,当我发送一些设备(或多或少 1-20 个)时它没有问题,但是当我必须发送批量通知时(3000+) 它给我以下错误:

[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 conexiConnection 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 conexiConnection 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

我的代码如下:

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

有什么问题吗?可以连接到 Apple 服务器的设备和连接的最大数量是多少?欢迎任何帮助。

我找到了我的问题的解决方案,代码工作正常,在与系统管理员交谈后我们可以看到这是服务器配置的问题,因为根据 link of apple 要能够发送通知,必须考虑以下因素:

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

这样:

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.

此外:

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.

因此,系统管理员通过配置防火墙来允许这些连接来解决所有问题。我希望它对某人有所帮助。