All Projects → jchambers → Pushy

jchambers / Pushy

Licence: mit
A Java library for sending APNs (iOS/macOS/Safari) push notifications

Programming Languages

java
68154 projects - #9 most used programming language

Projects that are alternatives of or similar to Pushy

Socket.io Push
整合了小米,华为,友盟,谷歌,苹果推送的统一解决方案
Stars: ✭ 605 (-55.28%)
Mutual labels:  notifications, push-notifications, apns
mobile-messaging-sdk-ios
Mobile Messaging SDK for iOS
Stars: ✭ 45 (-96.67%)
Mutual labels:  notifications, push-notifications, apns
Net Core Push Notifications
Lightweight .NET Core Push Notifications for Android and iOS
Stars: ✭ 105 (-92.24%)
Mutual labels:  notifications, push-notifications, apns
Onesignal Ios Sdk
OneSignal is a free push notification service for mobile apps. This plugin makes it easy to integrate your native iOS app with OneSignal. https://onesignal.com
Stars: ✭ 370 (-72.65%)
Mutual labels:  notifications, push-notifications, apns
Onesignal Unity Sdk
OneSignal is a free push notification service for mobile apps. This plugin makes it easy to integrate your Unity app with OneSignal. https://onesignal.com
Stars: ✭ 161 (-88.1%)
Mutual labels:  notifications, push-notifications, apns
Notificationpusher
Standalone PHP library for easy devices notifications push.
Stars: ✭ 1,143 (-15.52%)
Mutual labels:  notifications, push-notifications, apns
Countly Sdk Android
Countly Product Analytics Android SDK
Stars: ✭ 626 (-53.73%)
Mutual labels:  notifications, push-notifications
Demo Progressive Web App
🎉 A demo for progressive web application with features like offline, push notifications, background sync etc,
Stars: ✭ 798 (-41.02%)
Mutual labels:  notifications, push-notifications
Node Gcm
A NodeJS wrapper library port to send data to Android devices via Google Cloud Messaging
Stars: ✭ 1,286 (-4.95%)
Mutual labels:  notifications, push-notifications
Onesignal Python
Python client for OneSignal push notification service
Stars: ✭ 33 (-97.56%)
Mutual labels:  notifications, push-notifications
Node Pushnotifications
Push notifications for GCM, APNS, MPNS, AMZ (automatic detection from device token)
Stars: ✭ 432 (-68.07%)
Mutual labels:  push-notifications, apns
Toot Relay
Relay that forwards web push notifications to APNs, built for Toot!.app but usable for anyone.
Stars: ✭ 18 (-98.67%)
Mutual labels:  notifications, apns
Pushkit
All the required components to set up independent web push notifications 🎈
Stars: ✭ 45 (-96.67%)
Mutual labels:  notifications, push-notifications
Countly Server
Countly helps you get insights from your application. Available self-hosted or on private cloud.
Stars: ✭ 4,857 (+258.98%)
Mutual labels:  notifications, push-notifications
Gaurun
General push notification server in Go
Stars: ✭ 804 (-40.58%)
Mutual labels:  push-notifications, apns
Airnotifier
Push Notifications Server for Human Beings.
Stars: ✭ 522 (-61.42%)
Mutual labels:  notifications, apns
Easynotifylibproject
Send firebase notifications to your users very easily: A new Android Lib
Stars: ✭ 31 (-97.71%)
Mutual labels:  notifications, push-notifications
Codehub Push
Push notification server built in Node.js for the iOS application CodeHub
Stars: ✭ 86 (-93.64%)
Mutual labels:  notifications, apns
Onesignal Ionic Example
Stars: ✭ 89 (-93.42%)
Mutual labels:  push-notifications, apns
React Native Onesignal
React Native Library for OneSignal Push Notifications Service
Stars: ✭ 1,270 (-6.13%)
Mutual labels:  notifications, push-notifications

pushy

Build/test Maven Central

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 have questions about using Pushy, please join us on the Pushy mailing list or take a look at the wiki. Thanks!

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.

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.14.2</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:

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.36.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:

  1. The gateway accepts the notification and will attempt to deliver it to the destination device.
  2. 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.
  3. The CompletableFuture fails 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 is invalid as of " + timestamp);
        });
    }
} catch (final ExecutionException e) {
    System.err.println("Failed to send push notification.");
    e.printStackTrace();
}

It's important to note that CompletableFuture has affordances for scheduling additional tasks to run when an operation is complete. Waiting for each individual push notification is inefficient in practice, and most users will be better served by adding follow-up tasks to the CompletableFuture instead of blocking until it completes. As an example:

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

All APNs clients—even those that have never sent a message—may allocate and hold on to system resources, and it's important to release them. APNs clients are intended to be persistent, long-lived resources; you definitely don't need to shut down a client after sending a notification (or even batch of notifications), but you'll want to shut down your client (or clients) when your application is shutting down:

final CompletableFuture<Void> closeFuture = apnsClient.close();

When shutting down, clients will wait for all sent-but-not-acknowledged notifications to receive a reply from the server. Notifications that have been passed to sendNotification but not yet sent to the server (i.e. notifications waiting in an internal queue) will fail immediately when disconnecting. Callers should generally make sure that all sent notifications have been acknowledged by the server before shutting down.

Performance and best practices

Making the most of your system resources for high-throughput applications always takes some effort. To guide you through the process, we've put together a wiki page covering some best practices for using Pushy. All of these points are covered in much more detail on the wiki, but in general, our recommendations are:

  • Treat ApnsClient instances as long-lived resources
  • Add follow-up tasks to CompletableFutures if you want to track the status of your push notifications
  • Use a flow control strategy to avoid enqueueing push notifications faster than the server can respond
  • Choose a number of threads and concurrent connections that balances CPU time and network throughput

Metrics

Pushy includes an interface for monitoring metrics that provide insight into clients' behavior and performance. You can write your own implementation of the ApnsClientMetricsListener interface to record and report metrics. We also provide metrics listeners that gather and report metrics using the Dropwizard Metrics library and using the Micrometer application monitoring facade as separate modules. To begin receiving metrics, set a listener when building a new client:

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

Please note that the metric-handling methods in your listener implementation should never call blocking code. It's appropriate to increment counters directly in the handler methods, but calls to databases or remote monitoring endpoints should be dispatched to separate threads.

Using a proxy

If you need to use a proxy for outbound connections, you may specify a ProxyHandlerFactory when building your ApnsClient instance. Concrete implementations of ProxyHandlerFactory are provided for HTTP, SOCKS4, and SOCKS5 proxies.

An example:

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

If using HTTP proxies configured via JVM system properties, you can also use:

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

Logging

Pushy uses SLF4J for logging. If you're not already familiar with it, SLF4J is a facade that allows users to choose which logging library to use at deploy time by adding a specific "binding" to the classpath. To avoid making the choice for you, Pushy itself does not depend on any SLF4J bindings; you'll need to add one on your own (either by adding it as a dependency in your own project or by installing it directly). If you have no SLF4J bindings on your classpath, you'll probably see a warning that looks something like this:

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.

For more information, see the SLF4J user manual.

Pushy uses logging levels as follows:

Level Events logged
error Serious, unrecoverable errors; recoverable errors that likely indicate a bug in Pushy
warn Serious, but recoverable errors; errors that may indicate a bug in caller's code
info Important lifecycle events
debug Minor lifecycle events; expected exceptions
trace Individual IO operations

Using a mock server

Pushy includes a mock APNs server that callers may use in integration tests and benchmarks. It is not necessary to use a mock server (or any related classes) in normal operation.

To build a mock server, callers should use a MockApnsServerBuilder. All servers require a PushNotificationHandler (built by a PushNotificationHandlerFactory provided to the builder) that decides whether the mock server will accept or reject each incoming push notification. Pushy includes an AcceptAllPushNotificationHandlerFactory that is helpful for benchmarking and a ValidatingPushNotificationHandlerFactory that may be helpful for integration testing.

Callers may also provide a MockApnsServerListener when building a mock server; listeners are notified whenever the mock server accepts or rejects a notification from a client.

License and status

Pushy is available under the MIT License.

The current version of Pushy is 0.14.2. It's fully functional and widely used in production environments, but the public API may change significantly before a 1.0 release.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].