Skip to content

APNS

Vapor's Apple Push Notification Service (APNS) API makes it easy to authenticate and send push notifications to Apple devices. It's built on top of APNSwift.

Getting Started

Let's take a look at how you can get started using APNS.

Package

The first step to using APNS is adding the package to your dependencies.

// swift-tools-version:5.8
import PackageDescription

let package = Package(
    name: "my-app",
    dependencies: [
         // Other dependencies...
        .package(url: "https://github.com/vapor/apns.git", from: "4.0.0"),
    ],
    targets: [
        .target(name: "App", dependencies: [
            // Other dependencies...
            .product(name: "VaporAPNS", package: "apns")
        ]),
        // Other targets...
    ]
)

If you edit the manifest directly inside Xcode, it will automatically pick up the changes and fetch the new dependency when the file is saved. Otherwise, from Terminal, run swift package resolve to fetch the new dependency.

Configuration

The APNS module adds a new property apns to Application. To send push notifications, you will need to set the configuration property with your credentials.

import APNS
import VaporAPNS
import APNSCore

// Configure APNS using JWT authentication.
let apnsConfig = APNSClientConfiguration(
    authenticationMethod: .jwt(
        privateKey: try .loadFrom(string: "<#key.p8 content#>"),
        keyIdentifier: "<#key identifier#>",
        teamIdentifier: "<#team identifier#>"
    ),
    environment: .sandbox
)
app.apns.containers.use(
    apnsConfig,
    eventLoopGroupProvider: .shared(app.eventLoopGroup),
    responseDecoder: JSONDecoder(),
    requestEncoder: JSONEncoder(),
    as: .default
)

Fill in the placeholders with your credentials. The above example shows JWT-based auth using the .p8 key you get from Apple's developer portal. For TLS-based auth with a certificate, use the .tls authentication method:

authenticationMethod: .tls(
    privateKeyPath: <#path to private key#>,
    pemPath: <#path to pem file#>,
    pemPassword: <#optional pem password#>
)

Send

Once APNS is configured, you can send push notifications using apns.send method on Application or Request.

// Custom Codable Payload
struct Payload: Codable {
    let acme1: String
    let acme2: Int
}
// Create push notification Alert
let dt = "70075697aa918ebddd64efb165f5b9cb92ce095f1c4c76d995b384c623a258bb"
let payload = Payload(acme1: "hey", acme2: 2)
let alert = APNSAlertNotification(
    alert: .init(
        title: .raw("Hello"),
        subtitle: .raw("This is a test from vapor/apns")
    ),
    expiration: .immediately,
    priority: .immediately,
    topic: "<#my topic#>",
    payload: payload
)
// Send the notification
try! await req.apns.client.sendAlertNotification(
    alert, 
    deviceToken: dt, 
    deadline: .distantFuture
)

Use req.apns whenever you are inside of a route handler.

// Sends a push notification.
app.get("test-push") { req async throws -> HTTPStatus in
    try await req.apns.client.send(...)
    return .ok
}

The first parameter accepts the push notification alert and the second parameter is the target device token.

Alert

APNSAlertNotification is the actual metadata of the push notification alert to send. More details on the specifics of each property are provided here. They follow a one-to-one naming scheme listed in Apple's documentation

let alert = APNSAlertNotification(
    alert: .init(
        title: .raw("Hello"),
        subtitle: .raw("This is a test from vapor/apns")
    ),
    expiration: .immediately,
    priority: .immediately,
    topic: "<#my topic#>",
    payload: payload
)

This type can be passed directly to the send method.

Custom Notification Data

Apple provides engineers with the ability to add custom payload data to each notification. In order to facilitate this we accept Codable conformance to the payload parameter on all send apis.

// Custom Codable Payload
struct Payload: Codable {
    let acme1: String
    let acme2: Int
}

More Information

For more information on available methods, see APNSwift's README.