Pushy — это библиотека Java для отправки push-уведомлений APN (iOS, macOS и Safari).
Pushy отправляет push-уведомления с использованием протокола APN Apple на основе HTTP/2 и поддерживает как TLS, так и аутентификацию на основе токенов. Он отличается от других библиотек push-уведомлений акцентом на тщательную документацию, асинхронную работу и дизайн для работы в промышленном масштабе. С помощью Pushy можно легко и эффективно поддерживать несколько параллельных подключений к шлюзу APN для отправки большого количества уведомлений множеству различных приложений («тем»).
Мы считаем, что Pushy уже является лучшим инструментом для отправки push-уведомлений APN из приложений Java, и надеемся, что вы поможете нам сделать его еще лучше с помощью отчетов об ошибках и запросов на включение.
Если вам нужно простое приложение с графическим интерфейсом для отправки push-уведомлений в целях разработки или тестирования, вас также может заинтересовать родственный проект Pushy — Pushy Console.
Если вы используете Maven, вы можете добавить Pushy в свой проект, добавив в POM следующее объявление зависимости:
< dependency >
< groupId >com.eatthepath</ groupId >
< artifactId >pushy</ artifactId >
< version >0.15.4</ version >
</ dependency >
Если вы не используете Maven (или что-то еще, что понимает зависимости Maven, например Gradle), вы можете скачать Pushy как файл .jar
и добавить его непосредственно в свой проект. Вам также необходимо убедиться, что в вашем пути к классам есть зависимости времени выполнения Pushy. Они есть:
Для сборки и запуска Pushy требуется Java 8 или новее. Хотя это и не обязательно, пользователи могут выбрать использование netty-native в качестве поставщика SSL для повышения производительности. Чтобы использовать собственный поставщик, убедитесь, что netty-tcnative находится в вашем пути к классам. Пользователи Maven могут добавить зависимость в свой проект следующим образом:
< dependency >
< groupId >io.netty</ groupId >
< artifactId >netty-tcnative-boringssl-static</ artifactId >
< version >2.0.62.Final</ version >
< scope >runtime</ scope >
</ dependency >
Прежде чем вы сможете начать работу с Pushy, вам необходимо выполнить некоторые подготовительные работы с Apple, чтобы зарегистрировать свое приложение и получить необходимые сертификаты или ключи подписи (подробнее об этом чуть позже). Подробную информацию об этом процессе см. в разделе «Регистрация вашего приложения с помощью APN» документации Apple UserNotifications. Обратите внимание, что есть некоторые предостережения, особенно в macOS 10.13 (El Capitan).
Вообще говоря, клиенты APN должны каким-либо образом пройти аутентификацию на сервере APN, прежде чем они смогут отправлять push-уведомления. В настоящее время APN (и Pushy) поддерживают два метода аутентификации: аутентификацию на основе TLS и аутентификацию на основе токенов. Эти два подхода являются взаимоисключающими; вам нужно будет выбрать один или другой вариант для каждого клиента.
При аутентификации на основе TLS клиенты передают серверу сертификат TLS при подключении и могут отправлять уведомления в любую «тему», указанную в сертификате. Как правило, это означает, что один клиент может отправлять push-уведомления только в одно принимающее приложение.
После того как вы зарегистрировали свое приложение и получили необходимые сертификаты, первое, что вам нужно сделать, чтобы начать отправлять push-уведомления с помощью Pushy, — это создать ApnsClient
. Клиентам, использующим аутентификацию TLS, необходим сертификат и закрытый ключ для аутентификации на сервере APNs. Самый распространенный способ хранения сертификата и ключа — это защищенный паролем файл PKCS#12 (вы получите защищенный паролем файл .p12, если будете следовать инструкциям Apple на момент написания этой статьи). Чтобы создать клиент, который будет использовать аутентификацию на основе TLS:
final ApnsClient apnsClient = new ApnsClientBuilder ()
. setApnsServer ( ApnsClientBuilder . DEVELOPMENT_APNS_HOST )
. setClientCredentials ( new File ( "/path/to/certificate.p12" ), "p12-file-password" )
. build ();
При аутентификации на основе токенов клиенты по-прежнему подключаются к серверу, используя соединение, защищенное TLS, но не предоставляют серверу сертификат при подключении. Вместо этого клиенты включают криптографически подписанный токен в каждое отправляемое ими уведомление (не волнуйтесь — Pushy сделает это за вас автоматически). Клиенты могут отправлять push-уведомления в любую «тему», для которой у них есть действительный ключ подписи.
Чтобы начать работу с клиентом на основе токенов, вам необходимо получить ключ подписи (в некоторых контекстах также называемый закрытым ключом) от Apple. Получив ключ подписи, вы можете создать нового клиента:
final ApnsClient apnsClient = new ApnsClientBuilder ()
. setApnsServer ( ApnsClientBuilder . DEVELOPMENT_APNS_HOST )
. setSigningKey ( ApnsSigningKey . loadFromPkcs8File ( new File ( "/path/to/key.p8" ),
"TEAMID1234" , "KEYID67890" ))
. build ();
Клиенты APN Pushy поддерживают внутренний пул подключений к серверу APN и создают новые соединения по требованию. В результате клиенты не требуют явного запуска. Независимо от выбранного вами метода аутентификации, как только вы создали клиент, он готов начать отправку push-уведомлений. Как минимум, для push-уведомлений требуется токен устройства (который идентифицирует устройство назначения уведомления и отличается от токена аутентификации), тему и полезную нагрузку.
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 включает в себя SimpleApnsPayloadBuilder
, а конструкторы полезной нагрузки на основе Gson и Jackson доступны как отдельные модули. Полезные данные APN — это просто строки JSON, и вызывающие абоненты могут создавать полезные данные любым методом по своему выбору; хотя конструкторы полезной нагрузки Pushy могут быть удобными, вызывающие программы не обязаны их использовать.
Процесс отправки push-уведомления асинхронный; хотя процесс отправки уведомления и получения ответа от сервера может занять некоторое время, клиент сразу вернет CompletableFuture
. Вы можете использовать CompletableFuture
для отслеживания хода и конечного результата операции отправки. Обратите внимание, что отправка уведомления возвращает PushNotificationFuture
, который является подклассом CompletableFuture
и всегда содержит ссылку на отправленное уведомление.
final PushNotificationFuture < SimpleApnsPushNotification , PushNotificationResponse < SimpleApnsPushNotification >>
sendNotificationFuture = apnsClient . sendNotification ( pushNotification );
CompletableFuture
завершится в одном из трех случаев:
CompletableFuture
завершается с ошибкой с исключением. Обычно это следует рассматривать как временный сбой, и вызывающим абонентам следует попытаться отправить уведомление еще раз, когда проблема будет решена.Пример:
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 ();
}
Важно отметить, что CompletableFuture
позволяет планировать запуск дополнительных задач после завершения операции. Ожидание каждого отдельного push-уведомления на практике неэффективно, и большинству пользователей будет лучше, если добавить последующие задачи в CompletableFuture
вместо блокировки до их завершения. В качестве примера:
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 ();
}
});
Все клиенты APN — даже те, которые никогда не отправляли сообщения — могут выделять и удерживать системные ресурсы, и важно их освободить. Клиенты APN должны быть постоянными и долгоживущими ресурсами; вам определенно не нужно завершать работу клиента после отправки уведомления (или даже пакета уведомлений), но вы захотите закрыть свой клиент (или клиенты), когда ваше приложение закрывается:
final CompletableFuture < Void > closeFuture = apnsClient . close ();
При завершении работы клиенты будут ждать всех отправленных, но неподтвержденных уведомлений, чтобы получить ответ от сервера. Уведомления, которые были переданы в sendNotification
но еще не отправлены на сервер (т. е. уведомления, ожидающие во внутренней очереди), немедленно завершатся ошибкой при отключении. Обычно перед завершением работы вызывающие абоненты должны убедиться, что все отправленные уведомления подтверждены сервером.
Максимальное использование системных ресурсов для приложений с высокой пропускной способностью всегда требует определенных усилий. Чтобы помочь вам в этом процессе, мы создали вики-страницу, на которой описаны некоторые рекомендации по использованию Pushy. Все эти моменты гораздо более подробно освещены на вики, но в целом наши рекомендации таковы:
ApnsClient
как к долгоживущим ресурсам.CompletableFutures
, если вы хотите отслеживать статус своих push-уведомлений. Pushy включает в себя интерфейс для мониторинга показателей, который дает представление о поведении и производительности клиентов. Вы можете написать собственную реализацию интерфейса ApnsClientMetricsListener
для записи и составления отчетов о показателях. Мы также предоставляем прослушиватели метрик, которые собирают и сообщают о метриках с помощью библиотеки Dropwizard Metrics и фасада мониторинга приложений Micrometer в виде отдельных модулей. Чтобы начать получать метрики, установите прослушиватель при создании нового клиента:
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 ();
Обратите внимание, что методы обработки метрик в вашей реализации прослушивателя никогда не должны вызывать код блокировки. Уместно увеличивать счетчики непосредственно в методах-обработчиках, но вызовы к базам данных или конечным точкам удаленного мониторинга должны распределяться по отдельным потокам.
Если вам нужно использовать прокси-сервер для исходящих подключений, вы можете указать ProxyHandlerFactory
при создании экземпляра ApnsClient
. Конкретные реализации ProxyHandlerFactory
предоставляются для прокси-серверов HTTP, SOCKS4 и SOCKS5.
Пример:
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 ();
Если вы используете HTTP-прокси, настроенные через свойства системы JVM, вы также можете использовать:
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 использует SLF4J для ведения журнала. Если вы еще не знакомы с этим, SLF4J — это фасад, который позволяет пользователям выбирать, какую библиотеку журналирования использовать во время развертывания, добавляя определенную «привязку» к пути к классам. Чтобы не делать выбор за вас, Pushy сам по себе не зависит от каких-либо привязок SLF4J; вам нужно будет добавить его самостоятельно (либо добавив его как зависимость в свой собственный проект, либо установив его напрямую). Если в вашем пути к классам нет привязок SLF4J, вы, вероятно, увидите предупреждение, которое выглядит примерно так:
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.
Дополнительную информацию см. в руководстве пользователя SLF4J.
Pushy использует уровни журналирования следующим образом:
Уровень | Зарегистрированные события |
---|---|
error | Серьезные, неисправимые ошибки; исправимые ошибки, которые, вероятно, указывают на ошибку в Pushy |
warn | Серьезные, но исправимые ошибки; ошибки, которые могут указывать на ошибку в коде вызывающего абонента |
info | Важные события жизненного цикла |
debug | Второстепенные события жизненного цикла; ожидаемые исключения |
trace | Отдельные операции ввода-вывода |
Pushy включает в себя макет сервера APN, который вызывающие абоненты могут использовать в интеграционных тестах и тестах. При нормальной работе нет необходимости использовать фиктивный сервер (или любые связанные с ним классы).
Чтобы создать макет сервера, вызывающие стороны должны использовать MockApnsServerBuilder
. Всем серверам требуется PushNotificationHandler
(созданный PushNotificationHandlerFactory
предоставленный разработчику), который решает, будет ли макетный сервер принимать или отклонять каждое входящее push-уведомление. Pushy включает AcceptAllPushNotificationHandlerFactory
, который полезен для сравнительного анализа, и ValidatingPushNotificationHandlerFactory
, который может быть полезен для интеграционного тестирования.
Вызывающие стороны также могут предоставить MockApnsServerListener
при создании фиктивного сервера; слушатели уведомляются всякий раз, когда макетный сервер принимает или отклоняет уведомление от клиента.
Pushy доступен по лицензии MIT.
Текущая версия Pushy — 0.15.4. Он полностью функционален и широко используется в производственных средах, но общедоступный API может существенно измениться до выпуска версии 1.0.