Pushy
A Java library for sending APNs (iOS/macOS/Safari) push notifications
Install / Use
/learn @jchambers/PushyREADME
pushy
Pushy is a Java library for sending APNs (iOS, macOS, and Safari) push notifications.
Pushy sends push notifications using Apple's HTTP/2-based APNs protocol and supports both TLS and token-based authentication. It distinguishes itself from other push notification libraries with a focus on thorough documentation, asynchronous operation, and design for industrial-scale operation. With Pushy, it's easy and efficient to maintain multiple parallel connections to the APNs gateway to send large numbers of notifications to many different applications ("topics").
We believe that Pushy is already the best tool for sending APNs push notifications from Java applications, and we hope you'll help us make it even better via bug reports and pull requests.
If you need a simple GUI application for sending push notifications for development or testing purposes, you might also be interested in Pushy's sister project, Pushy Console.
Quick links
- API documentation
- Discussions (for general support and questions)
- Issues (for bug reports and feature requests)
Getting Pushy
If you use Maven, you can add Pushy to your project by adding the following dependency declaration to your POM:
<dependency>
<groupId>com.eatthepath</groupId>
<artifactId>pushy</artifactId>
<version>0.15.4</version>
</dependency>
If you don't use Maven (or something else that understands Maven dependencies, like Gradle), you can download Pushy as a .jar file and add it to your project directly. You'll also need to make sure you have Pushy's runtime dependencies on your classpath. They are:
- netty 4.1.119
- slf4j 1.7 (and possibly an SLF4J binding, as described in the logging section below)
- fast-uuid 0.1
Pushy itself requires Java 8 or newer to build and run. While not required, users may choose to use netty-native as an SSL provider for enhanced performance. To use a native provider, make sure netty-tcnative is on your classpath. Maven users may add a dependency to their project as follows:
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-tcnative-boringssl-static</artifactId>
<version>2.0.62.Final</version>
<scope>runtime</scope>
</dependency>
Authenticating with the APNs server
Before you can get started with Pushy, you'll need to do some provisioning work with Apple to register your app and get the required certificates or signing keys (more on these shortly). For details on this process, please see the Registering Your App with APNs section of Apple's UserNotifications documentation. Please note that there are some caveats, particularly under macOS 10.13 (El Capitan).
Generally speaking, APNs clients must authenticate with the APNs server by some means before they can send push notifications. Currently, APNs (and Pushy) supports two authentication methods: TLS-based authentication and token-based authentication. The two approaches are mutually-exclusive; you'll need to pick one or the other for each client.
TLS authentication
In TLS-based authentication, clients present a TLS certificate to the server when connecting, and may send notifications to any "topic" named in the certificate. Generally, this means that a single client can only send push notifications to a single receiving app.
Once you've registered your app and have the requisite certificates, the first thing you'll need to do to start sending push notifications with Pushy is to create an ApnsClient. Clients using TLS authentication need a certificate and private key to authenticate with the APNs server. The most common way to store the certificate and key is in a password-protected PKCS#12 file (you'll wind up with a password-protected .p12 file if you follow Apple's instructions at the time of this writing). To create a client that will use TLS-based authentication:
final ApnsClient apnsClient = new ApnsClientBuilder()
.setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST)
.setClientCredentials(new File("/path/to/certificate.p12"), "p12-file-password")
.build();
Token authentication
In token-based authentication, clients still connect to the server using a TLS-secured connection, but do not present a certificate to the server when connecting. Instead, clients include a cryptographically-signed token with each notification they send (don't worry—Pushy handles this for you automatically). Clients may send push notifications to any "topic" for which they have a valid signing key.
To get started with a token-based client, you'll need to get a signing key (also called a private key in some contexts) from Apple. Once you have your signing key, you can create a new client:
final ApnsClient apnsClient = new ApnsClientBuilder()
.setApnsServer(ApnsClientBuilder.DEVELOPMENT_APNS_HOST)
.setSigningKey(ApnsSigningKey.loadFromPkcs8File(new File("/path/to/key.p8"),
"TEAMID1234", "KEYID67890"))
.build();
Sending push notifications
Pushy's APNs clients maintain an internal pool of connections to the APNs server and create new connections on demand. As a result, clients do not need to be started explicitly. Regardless of the authentication method you choose, once you've created a client, it's ready to start sending push notifications. At minimum, push notifications need a device token (which identifies the notification's destination device and is a distinct idea from an authentication token), a topic, and a payload.
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 includes a SimpleApnsPayloadBuilder, and payload builders based on Gson and Jackson are available as separate modules. APNs payloads are just JSON strings, and callers may produce payloads by the method of their choice; while Pushy's payload builders may be convenient, callers are not obligated to use them.
The process of sending a push notification is asynchronous; although the process of sending a notification and getting a reply from the server may take some time, the client will return a CompletableFuture right away. You can use that CompletableFuture to track the progress and eventual outcome of the sending operation. Note that sending a notification returns a PushNotificationFuture, which is a subclass of CompletableFuture that always holds a reference to the notification that was sent.
final PushNotificationFuture<SimpleApnsPushNotification, PushNotificationResponse<SimpleApnsPushNotification>>
sendNotificationFuture = apnsClient.sendNotification(pushNotification);
The CompletableFuture will complete in one of three circumstances:
- The gateway accepts the notification and will attempt to deliver it to the destination device.
- The gateway rejects the notification; this should be considered a permanent failure, and the notification should not be sent again. Additionally, the APNs gateway may indicate a timestamp at which the destination token became invalid. If that happens, you should stop trying to send any notification to that token unless the token has been re-registered since that timestamp.
- The
CompletableFuturefails with an exception. This should generally be considered a temporary failure, and callers should try to send the notification again when the problem has been resolved.
An example:
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
Related Skills
node-connect
336.9kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.0kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
336.9kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.0kCommit, push, and open a PR
