APNSwift 5.0.0 Beta Release

I'm happy to announce that APNSwift 5.0.0-beta.1 has just been tagged. This is probably the most comprehensive release to date, providing a rich semantic API to guarantee you know how to send push notifications in your application. When I started on APNSwift 3 years ago, the swift on the server eco system was very different. Under the hood, the first implementation was SwiftNIO 1, followed quickly by SwiftNIO 2.

Now that things have grown so immensely, the eco system is able to provide APNSwift with even broader set of tools. With this release we've migrated to using AsyncHTTPClient, removing APNSwift's channel handlers and complex SSL implementations.

Huge Thanks

Many contributors have helped APNSwift be the goto package for swift on the server push notifications, but with this release we give a huge thanks to the immense efforts by @FranzBusch. Without them we would not have this brand new rich set of API's that make APNSwift safer, and more reliable.

Foundational changes

APNSwift is built with a layered approach. It exposes three tiers of API's.

  1. A raw API that takes basic types such as String's
  2. A slightly more semantically safe API, which takes types, like APNSPriority, APNSPushType, APNSNotificationExpiration, etc.
  3. The safest API which takes fully semantic types such as APNSAlertNotification

We recommened using number 3, the semantically safest API to ensure your push notification is delivered correctly .

Here are the new send API's that provide a low barrier to entry for sending specific types of pushes.

  • sendAlertNotification
  • sendBackground
  • sendVoIP
  • sendFileProvider
  • sendLocationNotification
  • sendComplicationNotification

Previously the send api exposed a number of parameters for sending a push.

Old way

let alert = APNSwiftAlert(
    title: "title",
    subtitle: "subtitle",
    body: "body",
    titleLocKey: "titlelockey",
    titleLocArgs: ["titlelocarg1"],
    actionLocKey: "actionkey",
    locKey: "lockey",
    locArgs: ["locarg1"],
    launchImage: "launchImage"
)

let payload = APNSwiftPayload(alert: alert, sound: .normal("pong.wav"))
try await req.apns.client.send(
    payload,
    to: "98AAD4A2398DDC58595F02FA307DF9A15C18B6111D1B806949549085A8E6A55D"
)

New way

struct Payload: Encodable {
    let myCustomKey = "myCustomValue"
}
try await client.sendAlertNotification(
    .init(
        alert: .init(
            title: .raw("Simple Alert"),
            subtitle: .raw("Subtitle"),
            body: .raw("Body"),
            launchImage: nil
        ),
        expiration: .immediately,
        priority: .immediately,
        topic: "com.example",
        payload: Payload()
    ),
    deviceToken: deviceToken,
    deadline: .distantFuture,
    logger: logger
)

Custom environment

The biggest requested feature of APNSwift was the ability to jump between environments. While 4.0.0 did contain a release that could do this, 5.0.0 changed slightly. APNSClient now contains the environment so if you need to send to a specific environment, you can use multiple client configurations.

Additionally there are a number of improvements to the documentation and a whole new suite of tests.

What if what you built doesn't support what I need.

APNSwift provides the ability to send raw payloads. You can use Data, ByteBuffer, DispatchData, Array Though this is to be used with caution. APNSwift cannot gurantee delivery if you do not have the correct payload. For more information see: Creating APN Payload

If you do end up using either of these, please open a PR so we can get a semantic version available to everyone!

/// Extremely Raw,
try await client.send(
    payload: payload, 
    deviceToken: token, 
    pushType: "alert", 
    deadline: .distantFuture
)

/// or a little safer but still raw
try await client.send(
    payload: payload, 
    deviceToken: token, 
    pushType: .alert, 
    expiration: .immediatly, 
    priority: .immediatly, 
    deadline: .distantFuture
)

There is more information in the repo, including an Example project. We would love to know what everyone thinks. So chime in below :point_down:

13 Likes

@kylebrowning Thanks for doing the work over all the years! The ecosystem has come a long way and APNSwift has always kept up.
I am happy with the new APIs and layering system we came up with. Looking forward to the feedback!

5 Likes

Fantastic work @kylebrowning, @FranzBusch and the rest of the community! I remember that almost since day 1 of APNSwift we wanted it to use AsyncHTTPClient because writing a HTTP/2 client is no small feat (even with all the protocol implementations provided by SwiftNIO).

But up until earlier this year, AsyncHTTPClient didn't actually support HTTP/2.

But now, thanks to a lot of work by @fabianfett, @dnadoba and many others (for example @lukasa who wrote the lion share of SwiftNIO's HTTP/2 implementation which is what powers AsyncHTTPClient) the HTTP/2 support has landed and is good enough for APNSwift to use it directly. This is fantastic news, less code in a package like APNSwift and more sharing across the ecosystem brings so many benefits!

tl;dr: Well done Swift on Server community!

12 Likes