Pushy es una biblioteca de Java para enviar notificaciones push de APN (iOS, macOS y Safari).
Pushy envía notificaciones automáticas utilizando el protocolo APN basado en HTTP/2 de Apple y admite autenticación TLS y basada en token. Se distingue de otras bibliotecas de notificaciones automáticas por su enfoque en la documentación exhaustiva, la operación asincrónica y el diseño para operación a escala industrial. Con Pushy, es fácil y eficiente mantener múltiples conexiones paralelas a la puerta de enlace APN para enviar una gran cantidad de notificaciones a muchas aplicaciones diferentes ("temas").
Creemos que Pushy ya es la mejor herramienta para enviar notificaciones automáticas de APN desde aplicaciones Java y esperamos que nos ayude a mejorarla aún más mediante informes de errores y solicitudes de extracción.
Si necesita una aplicación GUI simple para enviar notificaciones automáticas con fines de desarrollo o prueba, es posible que también le interese el proyecto hermano de Pushy, Pushy Console.
Si usa Maven, puede agregar Pushy a su proyecto agregando la siguiente declaración de dependencia a su POM:
< dependency >
< groupId >com.eatthepath</ groupId >
< artifactId >pushy</ artifactId >
< version >0.15.4</ version >
</ dependency >
Si no usa Maven (u otra cosa que comprenda las dependencias de Maven, como Gradle), puede descargar Pushy como un archivo .jar
y agregarlo directamente a su proyecto. También deberás asegurarte de tener las dependencias de tiempo de ejecución de Pushy en tu classpath. Ellos son:
Pushy en sí requiere Java 8 o posterior para compilarse y ejecutarse. Si bien no es obligatorio, los usuarios pueden optar por utilizar netty-native como proveedor de SSL para mejorar el rendimiento. Para utilizar un proveedor nativo, asegúrese de que netty-tcnative esté en su classpath. Los usuarios de Maven pueden agregar una dependencia a su proyecto de la siguiente manera:
< dependency >
< groupId >io.netty</ groupId >
< artifactId >netty-tcnative-boringssl-static</ artifactId >
< version >2.0.62.Final</ version >
< scope >runtime</ scope >
</ dependency >
Antes de comenzar con Pushy, deberá realizar algunos trabajos de aprovisionamiento con Apple para registrar su aplicación y obtener los certificados o claves de firma necesarios (más sobre esto en breve). Para obtener detalles sobre este proceso, consulte la sección Registro de su aplicación con APN de la documentación de Notificaciones de usuario de Apple. Tenga en cuenta que existen algunas advertencias, particularmente en macOS 10.13 (El Capitan).
En términos generales, los clientes de APN deben autenticarse con el servidor de APN de algún modo antes de poder enviar notificaciones automáticas. Actualmente, los APN (y Pushy) admiten dos métodos de autenticación: autenticación basada en TLS y autenticación basada en token. Los dos enfoques son mutuamente excluyentes; deberás elegir uno u otro para cada cliente.
En la autenticación basada en TLS, los clientes presentan un certificado TLS al servidor cuando se conectan y pueden enviar notificaciones a cualquier "tema" nombrado en el certificado. Generalmente, esto significa que un único cliente solo puede enviar notificaciones automáticas a una única aplicación receptora.
Una vez que haya registrado su aplicación y tenga los certificados necesarios, lo primero que deberá hacer para comenzar a enviar notificaciones push con Pushy es crear un ApnsClient
. Los clientes que utilizan la autenticación TLS necesitan un certificado y una clave privada para autenticarse con el servidor APN. La forma más común de almacenar el certificado y la clave es en un archivo PKCS#12 protegido con contraseña (terminará con un archivo .p12 protegido con contraseña si sigue las instrucciones de Apple al momento de escribir este artículo). Para crear un cliente que utilizará autenticación basada en TLS:
final ApnsClient apnsClient = new ApnsClientBuilder ()
. setApnsServer ( ApnsClientBuilder . DEVELOPMENT_APNS_HOST )
. setClientCredentials ( new File ( "/path/to/certificate.p12" ), "p12-file-password" )
. build ();
En la autenticación basada en token, los clientes aún se conectan al servidor mediante una conexión segura TLS, pero no presentan un certificado al servidor cuando se conectan. En cambio, los clientes incluyen un token firmado criptográficamente con cada notificación que envían (no se preocupe, Pushy maneja esto automáticamente). Los clientes pueden enviar notificaciones automáticas a cualquier "tema" para el cual tengan una clave de firma válida.
Para comenzar con un cliente basado en token, necesitará obtener una clave de firma (también llamada clave privada en algunos contextos) de Apple. Una vez que tenga su clave de firma, puede crear un nuevo cliente:
final ApnsClient apnsClient = new ApnsClientBuilder ()
. setApnsServer ( ApnsClientBuilder . DEVELOPMENT_APNS_HOST )
. setSigningKey ( ApnsSigningKey . loadFromPkcs8File ( new File ( "/path/to/key.p8" ),
"TEAMID1234" , "KEYID67890" ))
. build ();
Los clientes APN de Pushy mantienen un grupo interno de conexiones al servidor APN y crean nuevas conexiones a pedido. Como resultado, no es necesario iniciar los clientes explícitamente. Independientemente del método de autenticación que elija, una vez que haya creado un cliente, estará listo para comenzar a enviar notificaciones automáticas. Como mínimo, las notificaciones push necesitan un token de dispositivo (que identifica el dispositivo de destino de la notificación y es una idea distinta de un token de autenticación), un tema y una carga útil.
final SimpleApnsPushNotification pushNotification ;
{
final ApnsPayloadBuilder payloadBuilder = new SimpleApnsPayloadBuilder ();
payloadBuilder . setAlertBody ( "Example!" );
final String payload = payloadBuilder . build ();
final String token = TokenUtil . sanitizeTokenString ( "<efc7492 bdbd8209>" );
pushNotification = new SimpleApnsPushNotification ( token , "com.example.myApp" , payload );
}
Pushy incluye SimpleApnsPayloadBuilder
y los creadores de carga útil basados en Gson y Jackson están disponibles como módulos separados. Las cargas útiles de APN son solo cadenas JSON y las personas que llaman pueden producir cargas útiles mediante el método de su elección; Si bien los creadores de carga útil de Pushy pueden ser convenientes, las personas que llaman no están obligadas a utilizarlos.
El proceso de envío de una notificación push es asincrónico; Aunque el proceso de enviar una notificación y obtener una respuesta del servidor puede llevar algún tiempo, el cliente devolverá un CompletableFuture
de inmediato. Puede utilizar CompletableFuture
para realizar un seguimiento del progreso y el resultado final de la operación de envío. Tenga en cuenta que enviar una notificación devuelve PushNotificationFuture
, que es una subclase de CompletableFuture
que siempre contiene una referencia a la notificación que se envió.
final PushNotificationFuture < SimpleApnsPushNotification , PushNotificationResponse < SimpleApnsPushNotification >>
sendNotificationFuture = apnsClient . sendNotification ( pushNotification );
CompletableFuture
se completará en una de tres circunstancias:
CompletableFuture
falla con una excepción. Por lo general, esto debe considerarse una falla temporal y las personas que llaman deben intentar enviar la notificación nuevamente cuando el problema se haya resuelto.Un ejemplo:
try {
final PushNotificationResponse < SimpleApnsPushNotification > pushNotificationResponse =
sendNotificationFuture . get ();
if ( pushNotificationResponse . isAccepted ()) {
System . out . println ( "Push notification accepted by APNs gateway." );
} else {
System . out . println ( "Notification rejected by the APNs gateway: " +
pushNotificationResponse . getRejectionReason ());
pushNotificationResponse . getTokenInvalidationTimestamp (). ifPresent ( timestamp -> {
System . out . println ( " t …and the token is invalid as of " + timestamp );
});
}
} catch ( final ExecutionException e ) {
System . err . println ( "Failed to send push notification." );
e . printStackTrace ();
}
Es importante tener en cuenta que CompletableFuture
tiene posibilidades para programar tareas adicionales para que se ejecuten cuando se completa una operación. Esperar cada notificación push individual es ineficiente en la práctica, y la mayoría de los usuarios estarán mejor atendidos si agregan tareas de seguimiento a CompletableFuture
en lugar de bloquear hasta que se complete. Como ejemplo:
sendNotificationFuture . whenComplete (( response , cause ) -> {
if ( response != null ) {
// Handle the push notification response as before from here.
} else {
// Something went wrong when trying to send the notification to the
// APNs server. Note that this is distinct from a rejection from
// the server, and indicates that something went wrong when actually
// sending the notification or waiting for a reply.
cause . printStackTrace ();
}
});
Todos los clientes de APN (incluso aquellos que nunca han enviado un mensaje) pueden asignar y conservar recursos del sistema, y es importante liberarlos. Los clientes de APN están destinados a ser recursos persistentes y de larga duración; Definitivamente no necesita cerrar un cliente después de enviar una notificación (o incluso un lote de notificaciones), pero querrá cerrar su cliente (o clientes) cuando su aplicación se esté cerrando:
final CompletableFuture < Void > closeFuture = apnsClient . close ();
Al apagar, los clientes esperarán a que todas las notificaciones enviadas pero no reconocidas reciban una respuesta del servidor. Las notificaciones que se pasaron a sendNotification
pero que aún no se enviaron al servidor (es decir, notificaciones en espera en una cola interna) fallarán inmediatamente al desconectarse. Por lo general, las personas que llaman deben asegurarse de que el servidor haya reconocido todas las notificaciones enviadas antes de apagarse.
Aprovechar al máximo los recursos de su sistema para aplicaciones de alto rendimiento siempre requiere algo de esfuerzo. Para guiarlo a través del proceso, hemos creado una página wiki que cubre algunas de las mejores prácticas para usar Pushy. Todos estos puntos se tratan con mucho más detalle en la wiki, pero en general, nuestras recomendaciones son:
ApnsClient
como recursos de larga duraciónCompletableFutures
si desea realizar un seguimiento del estado de sus notificaciones automáticas Pushy incluye una interfaz para monitorear métricas que brindan información sobre el comportamiento y el desempeño de los clientes. Puede escribir su propia implementación de la interfaz ApnsClientMetricsListener
para registrar e informar métricas. También proporcionamos detectores de métricas que recopilan e informan métricas utilizando la biblioteca Dropwizard Metrics y utilizando la fachada de monitoreo de la aplicación Micrometer como módulos separados. Para comenzar a recibir métricas, configure un oyente al crear un nuevo cliente:
final ApnsClient apnsClient = new ApnsClientBuilder ()
. setApnsServer ( ApnsClientBuilder . DEVELOPMENT_APNS_HOST )
. setSigningKey ( ApnsSigningKey . loadFromPkcs8File ( new File ( "/path/to/key.p8" ),
"TEAMID1234" , "KEYID67890" ))
. setMetricsListener ( new MyCustomMetricsListener ())
. build ();
Tenga en cuenta que los métodos de manejo de métricas en su implementación de escucha nunca deben llamar a código de bloqueo. Es apropiado incrementar los contadores directamente en los métodos del controlador, pero las llamadas a bases de datos o puntos finales de monitoreo remoto deben enviarse a subprocesos separados.
Si necesita utilizar un proxy para conexiones salientes, puede especificar ProxyHandlerFactory
al crear su instancia ApnsClient
. Se proporcionan implementaciones concretas de ProxyHandlerFactory
para proxies HTTP, SOCKS4 y SOCKS5.
Un ejemplo:
final ApnsClient apnsClient = new ApnsClientBuilder ()
. setApnsServer ( ApnsClientBuilder . DEVELOPMENT_APNS_HOST )
. setSigningKey ( ApnsSigningKey . loadFromPkcs8File ( new File ( "/path/to/key.p8" ),
"TEAMID1234" , "KEYID67890" ))
. setProxyHandlerFactory ( new Socks5ProxyHandlerFactory (
new InetSocketAddress ( "my.proxy.com" , 1080 ), "username" , "password" ))
. build ();
Si utiliza servidores proxy HTTP configurados a través de las propiedades del sistema JVM, también puede utilizar:
final ApnsClient apnsClient = new ApnsClientBuilder ()
. setApnsServer ( ApnsClientBuilder . DEVELOPMENT_APNS_HOST )
. setSigningKey ( ApnsSigningKey . loadFromPkcs8File ( new File ( "/path/to/key.p8" ),
"TEAMID1234" , "KEYID67890" ))
. setProxyHandlerFactory ( HttpProxyHandlerFactory . fromSystemProxies (
ApnsClientBuilder . DEVELOPMENT_APNS_HOST ))
. build ();
Pushy usa SLF4J para iniciar sesión. Si aún no está familiarizado con él, SLF4J es una fachada que permite a los usuarios elegir qué biblioteca de registro usar en el momento de la implementación agregando un "enlace" específico al classpath. Para evitar tomar la decisión por usted, Pushy no depende de ningún enlace SLF4J; deberá agregar uno usted mismo (ya sea agregándolo como una dependencia en su propio proyecto o instalándolo directamente). Si no tiene enlaces SLF4J en su classpath, probablemente verá una advertencia similar a esta:
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
Para obtener más información, consulte el manual de usuario de SLF4J.
Pushy usa niveles de registro de la siguiente manera:
Nivel | Eventos registrados |
---|---|
error | Errores graves e irrecuperables; errores recuperables que probablemente indican un error en Pushy |
warn | Errores graves pero recuperables; errores que pueden indicar un error en el código de la persona que llama |
info | Eventos importantes del ciclo de vida |
debug | Eventos menores del ciclo de vida; excepciones esperadas |
trace | Operaciones de E/S individuales |
Pushy incluye un servidor APN simulado que las personas que llaman pueden utilizar en pruebas de integración y puntos de referencia. No es necesario utilizar un servidor simulado (o cualquier clase relacionada) en funcionamiento normal.
Para crear un servidor simulado, las personas que llaman deben usar MockApnsServerBuilder
. Todos los servidores requieren un PushNotificationHandler
(creado por PushNotificationHandlerFactory
proporcionado al constructor) que decide si el servidor simulado aceptará o rechazará cada notificación push entrante. Pushy incluye AcceptAllPushNotificationHandlerFactory
que es útil para realizar evaluaciones comparativas y ValidatingPushNotificationHandlerFactory
que puede ser útil para las pruebas de integración.
Las personas que llaman también pueden proporcionar un MockApnsServerListener
al crear un servidor simulado; Los oyentes reciben una notificación cada vez que el servidor simulado acepta o rechaza una notificación de un cliente.
Pushy está disponible bajo la licencia MIT.
La versión actual de Pushy es 0.15.4. Es completamente funcional y se usa ampliamente en entornos de producción, pero la API pública puede cambiar significativamente antes de la versión 1.0.