📱HTTP/2 Apple Push Notification Service built with swift - send push notifications to iOS, iPadOS, tvOS, macOS, watchOS, visionOS, and Safari!
843
stars
287
commits
Swift
primary language
Aug 14, 2026
updated
A non-blocking Swift module for sending remote Apple Push Notification requests to APNS built on AsyncHttpClient.
To install APNSwift, just add the package as a dependency in your Package.swift.
dependencies: [
.package(url: "https://github.com/kylebrowning/APNSwift.git", from: "7.0.0"),
]
APNSwift aims to provide semantically correct structures to sending push notifications. You first need to setup a APNSClient. To do that youll need to know your authentication method
let client = APNSClient(
configuration: .init(
authenticationMethod: .jwt(
privateKey: try .init(pemRepresentation: privateKey),
keyIdentifier: keyIdentifier,
teamIdentifier: teamIdentifier
),
environment: .development
),
eventLoopGroupProvider: .createNew,
responseDecoder: JSONDecoder(),
requestEncoder: JSONEncoder()
)
// Shutdown the client when done
try await client.shutdown()
All notifications require a payload, but that payload can be empty. Payload just needs to conform to Encodable
struct Payload: Codable {}
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.app.bundle",
payload: Payload()
),
deviceToken: "device-token"
)
To successfully start a live activity:
Attributes and ContentState must match the live activity attributes provided in attributesTypealert must contain a title, body, and sound
let response = try await client.sendStartLiveActivityNotification(
.init (
expiration: .immediately,
priority: .immediately,
appID: "com.app.bundle",
contentState: contentState,
timestamp: Int(Date().timeIntervalSince1970),
attributes: attributes,
attributesType: "YourActivityAttributes",
alert: .init(
title: .raw("Your title"),
body: .raw(Your body),
sound: .fileName("default.aiff")
)
),
pushToStartToken: pushToStartToken
)
It requires sending ContentState matching with the live activity configuration to successfully update activity state. ContentState needs to conform to Encodable and Sendable.
try await client.sendLiveActivityNotification(
.init(
expiration: .immediately,
priority: .immediately,
appID: "com.app.bundle",
contentState: ContentState,
event: .update,
timestamp: Int(Date().timeIntervalSince1970)
),
deviceToken: activityPushToken
)
try await client.sendLiveActivityNotification(
.init(
expiration: .immediately,
priority: .immediately,
appID: "com.app.bundle",
contentState: ContentState,
event: .end,
timestamp: Int(Date().timeIntervalSince1970),
dismissalDate: .immediately // Optional to alter default behaviour
),
deviceToken: activityPushToken
)
APNSwift provides two authentication methods. jwt, and TLS.
jwt is preferred and recommend by Apple
These can be configured when created your APNSClientConfiguration
Notes: jwt requires an encrypted version of your .p8 file from Apple which comes in a pem format. If you're having trouble with your key being invalid please confirm it is a PEM file
openssl pkcs8 -nocrypt -in /path/to/my/key.p8 -out ~/Downloads/key.pem
Take a look at Program.swift
For an iOS example, open the example project within this repo.
Once inside configure your App Bundle ID and assign your development team. Build and run the ExampleApp to iOS Simulator, grab your device token, and plug it in to server example above. Background the app and run Program.swift
(top 30 of 42)
Swift
99.5%
📱HTTP/2 Apple Push Notification Service built with swift - send push notifications to iOS, iPadOS, tvOS, macOS, watchOS, visionOS, and Safari!
843
stars
287
commits
Swift
primary language
Aug 14, 2026
updated
A non-blocking Swift module for sending remote Apple Push Notification requests to APNS built on AsyncHttpClient.
To install APNSwift, just add the package as a dependency in your Package.swift.
dependencies: [
.package(url: "https://github.com/kylebrowning/APNSwift.git", from: "7.0.0"),
]
APNSwift aims to provide semantically correct structures to sending push notifications. You first need to setup a APNSClient. To do that youll need to know your authentication method
let client = APNSClient(
configuration: .init(
authenticationMethod: .jwt(
privateKey: try .init(pemRepresentation: privateKey),
keyIdentifier: keyIdentifier,
teamIdentifier: teamIdentifier
),
environment: .development
),
eventLoopGroupProvider: .createNew,
responseDecoder: JSONDecoder(),
requestEncoder: JSONEncoder()
)
// Shutdown the client when done
try await client.shutdown()
All notifications require a payload, but that payload can be empty. Payload just needs to conform to Encodable
struct Payload: Codable {}
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.app.bundle",
payload: Payload()
),
deviceToken: "device-token"
)
To successfully start a live activity:
Attributes and ContentState must match the live activity attributes provided in attributesTypealert must contain a title, body, and sound
let response = try await client.sendStartLiveActivityNotification(
.init (
expiration: .immediately,
priority: .immediately,
appID: "com.app.bundle",
contentState: contentState,
timestamp: Int(Date().timeIntervalSince1970),
attributes: attributes,
attributesType: "YourActivityAttributes",
alert: .init(
title: .raw("Your title"),
body: .raw(Your body),
sound: .fileName("default.aiff")
)
),
pushToStartToken: pushToStartToken
)
It requires sending ContentState matching with the live activity configuration to successfully update activity state. ContentState needs to conform to Encodable and Sendable.
try await client.sendLiveActivityNotification(
.init(
expiration: .immediately,
priority: .immediately,
appID: "com.app.bundle",
contentState: ContentState,
event: .update,
timestamp: Int(Date().timeIntervalSince1970)
),
deviceToken: activityPushToken
)
try await client.sendLiveActivityNotification(
.init(
expiration: .immediately,
priority: .immediately,
appID: "com.app.bundle",
contentState: ContentState,
event: .end,
timestamp: Int(Date().timeIntervalSince1970),
dismissalDate: .immediately // Optional to alter default behaviour
),
deviceToken: activityPushToken
)
APNSwift provides two authentication methods. jwt, and TLS.
jwt is preferred and recommend by Apple
These can be configured when created your APNSClientConfiguration
Notes: jwt requires an encrypted version of your .p8 file from Apple which comes in a pem format. If you're having trouble with your key being invalid please confirm it is a PEM file
openssl pkcs8 -nocrypt -in /path/to/my/key.p8 -out ~/Downloads/key.pem
Take a look at Program.swift
For an iOS example, open the example project within this repo.
Once inside configure your App Bundle ID and assign your development team. Build and run the ExampleApp to iOS Simulator, grab your device token, and plug it in to server example above. Background the app and run Program.swift
(top 30 of 42)
Swift
99.5%