Apple Push Notifications (APNs) Server-Side library.

Overview

Perfect-Notifications 简体中文

Get Involed with Perfect!

Swift 5.2 Platforms OS X | Linux License Apache

APNs remote Notifications for Perfect. This package adds push notification support to your server. Send notifications to iOS/macOS devices.

Building

This is a Swift Package manager based project. Add this repository as a dependency in your Package.swift file.

.package(url:"https://github.com/PerfectlySoft/Perfect-Notifications.git", from: "5.0.0")

Overview

This system runs on the server side. Typically at app launch, an Apple device will register with Apple's system for remote notifications. Doing so will return to the device an ID which can be used by external systems to address the device and send notifications through APNs.

When the device obtains its ID it will need to transmit it to your server. Your server will store this id and use it when sending notifications to one or more devices through APNs.

Obtain APNs Auth Key

To connect your server to Apple's push notification system you will first need to obtain an "APNs Auth Key". This key is used on your server to configure its APNs access. You can generate this key through your Apple developer account portal. Log in to your developer account and choose "Certificates, IDs & Profiles" from the menu. Then, under "Keys", choose "All".

If you haven't already created and downloaded the auth key, click "+" to create a new one. Enter a name for the key and make sure you select Apple Push Notifications service (APNs). This one key can be used for both development or production and can be used for any of your iOS/macOS apps.

Click "Continue", then "Confirm", then you will be given a chance to download the private key. You must download this key now and save the file. Also copy the "Key ID" shown in the same view. This will be a 10 character string.

Finally you will need to locate your developer team id. Click "Account" near the window's top. Select "Membership" in the menu. You will then be shown much of your personal information, including "Team ID". This is another 10 character string. Copy this value.

Server Configuration

To send notifications from your server your must have three pieces of information:

  1. The private key file which was downloaded
  2. The 10 character key id
  3. Your 10 character team id
  4. An iOS/macOS app id

These four pieces of information are used to perform push notifications. This information must reside on your server. You can store this information in any manner provided it can be used by the server. For simplicity, the rest of this example assumes that the private key file is in the server's working directory and that the two keys and the app id are embedded in the Swift code.

In your server Swift code, you must import PerfectNotifications. Then, before you start any HTTP servers or send any notifications you must add a "configuration" for the notifications you will be sending. This very simply ties your APNs keys to a name which you can then use later when pushing notifications.

import PerfectNotifications

// your app id. we use this as the configuration name, but they do not have to match
let notificationsAppId = "my.app.id"

let apnsKeyIdentifier = "AB90CD56XY"
let apnsTeamIdentifier = "YX65DC09BA"
let apnsPrivateKeyFilePath = "./APNsAuthKey_AB90CD56XY.p8"

NotificationPusher.addConfigurationAPNS(
	name: notificationsTestId, 
	production: false, // should be false when running pre-release app in debugger
	keyId: apnsKeyIdentifier, 
	teamId: apnsTeamIdentifier, 
	privateKeyPath: apnsPrivateKeyFilePath)

After the configuration has been added, notifications can be sent at any point. To do so, create a NotificationPusher with your app id, or "topic", then trigger a notification to one or more devices by calling its pushAPNS function:

let deviceIds: [String] = [...]
let n = NotificationPusher(apnsTopic: notificationsTestId)
n.pushAPNS(
	configurationName: notificationsTestId, 
	deviceTokens: deviceIds, 
	notificationItems: [.alertBody("Hello!"), .sound("default")]) {
		responses in
		print("\(responses)")
		...
}

The topic is required when creating a NotificationPusher. Additional optional parameters can be provided to customize the notification's expiration, priority and collapse-id. Consult Apple's APNS documentation for the semantics of these options.

Public API

The full public version 3.0 API for notification pusher follows:

public class NotificationPusher {
	
	/// Add an APNS configuration which can be later used to push notifications.
	public static func addConfigurationAPNS(
		name: String, 
		production: Bool, 
		keyId: String, 
		teamId: String, 
		privateKeyPath: String)

	/// Initialize given an apns-topic string.
	public init(
		apnsTopic: String,
		expiration: APNSExpiration = .immediate,
		priority: APNSPriority = .immediate,
		collapseId: String? = nil)
		
	/// Push one message to one device.
	/// Provide the previously set configuration name, device token.
	/// Provide a list of APNSNotificationItems.
	/// Provide a callback with which to receive the response.
	public func pushAPNS(
		configurationName: String, 
		deviceToken: String, 
		notificationItems: [APNSNotificationItem], 
		callback: @escaping (NotificationResponse) -> ())
	
	/// Push one message to multiple devices.
	/// Provide the previously set configuration name, and zero or more device tokens. The same message will be sent to each device.
	/// Provide a list of APNSNotificationItems.
	/// Provide a callback with which to receive the responses.
	public func pushAPNS(
		configurationName: String, deviceTokens: [String],
		notificationItems: [APNSNotificationItem],
		callback: @escaping ([NotificationResponse]) -> ())
}

The remaining structures, including APNSNotificationItem follow:

/// Items to configure an individual notification push.
public enum APNSNotificationItem {
    /// alert body child property
	case alertBody(String)
    /// alert title child property
	case alertTitle(String)
    /// alert title-loc-key
	case alertTitleLoc(String, [String]?)
    /// alert action-loc-key
	case alertActionLoc(String)
    /// alert loc-key
	case alertLoc(String, [String]?)
    /// alert launch-image
	case alertLaunchImage(String)
    /// aps badge key
	case badge(Int)
    /// aps sound key
	case sound(String)
    /// aps content-available key
	case contentAvailable
	/// aps category key
	case category(String)
	/// aps thread-id key
	case threadId(String)
    /// custom payload data
	case customPayload(String, Any)
    /// apn mutable-content key
	case mutableContent
}

public enum APNSPriority: Int {
	case immediate = 10
	case background = 5
}

/// Time in the future when the notification, if has not be able to be delivered, will expire.
public enum APNSExpiration {
	/// Discard the notification if it can't be immediately delivered.
	case immediate
	/// now + seconds
	case relative(Int)
	/// absolute UTC time since epoch
	case absolute(Int)
}

/// The response object given after a push attempt.
public struct NotificationResponse: CustomStringConvertible {
	/// The response code for the request.
	public let status: HTTPResponseStatus
	/// The response body data bytes.
	public let body: [UInt8]
	/// The body data bytes interpreted as JSON and decoded into a Dictionary.
	public var jsonObjectBody: [String:Any]
	/// The body data bytes converted to String.
	public var stringBody: String
	public var description: String
}

Additional Notes

APNs requests are made from your server to Apple's servers "api.development.push.apple.com" or "api.push.apple.com" on port 443. One request will be used when sending one notification to one or more devices. Each connection will remain open and will be reused when sending subsequent notifications. If a connection "goes away" or there are no idle connections that can be used then a new connection will be opened. This is in accordance with Apple's recommended usage of APNs and should provide the best throughput when dealing with many concurrent notification requests.

Consult Perfect-NotificationsExample for a client/server combination which can be easily configured with your own information to quickly get APNS notifications for your apps.

Further Information

For more information on the Perfect project, please visit perfect.org.

Comments
  • Added mutable-content to IOSNotificationItem to support Notification …

    Added mutable-content to IOSNotificationItem to support Notification …

    Added mutable-content to IOSNotificationItem to support Notification Service Extensions. The mutable-content flag must be set in the aps payload in order to support notification service extensions from remote notifications.

    opened by adamthecashew 2
  • Update 'Obtain APNs Auth Key' section in README.md

    Update 'Obtain APNs Auth Key' section in README.md

    Update 'Obtain APNs Auth Key' section in README.md to accurately reflect Apple Developer Portal current organization. APNs Auth Keys are now in a 'Keys' section rather than in 'Certificates'.

    opened by jeffreyfultonca 0
  • Adopt APNs changes with iOS 13

    Adopt APNs changes with iOS 13

    Adds the apns-push-type option to NotificationPusher, as required for watchOS 6 and recommended for all other platforms.

    The initialization of NotificationPusher receives an additional, optional argument of type APNSPushType, which is an enum specifying the type of the notification.

    Specifying the type adds the apns-push-type key with the appropriate value to the header of the notification request.

    The APNSPushType enum is commented with additional information about the different types, as detailed in Sending Notification Requests to APNs.

    Adding the option resolves issues with push notifications being dropped when no alert is included, specifically when sending content-available push updates.

    opened by christophhagen 0
  • Why it reading AuthKey from build path. Could you please explain? How we can configure build path on production

    Why it reading AuthKey from build path. Could you please explain? How we can configure build path on production

    Fatal error: The private key file "/AuthKey_A9HP4L5K6P.p8" does not exist. Current working directory: /Users/chandrakant/Library/Developer/Xcode/DerivedData/ashi-api-ackosslvopviteghopwhwturjxql/Build/Products/Debug/

    opened by awasthi027 0
  • Adopt iOS 13 APNS changes

    Adopt iOS 13 APNS changes

    Hello,

    Will there be a release which adopts the changes that Apple introduced in APNS for iOS 13+ and watch OS 6+?? I talk about the apns-push-type and apns-priority requirements.

    Thanx!

    opened by nick3389 1
  • Parameter production is unused

    Parameter production is unused

    public static func addConfigurationAPNS(name: String, production: Bool, certificatePath: String) { addConfigurationIOS(name: name) { net in guard File(certificatePath).exists else { fatalError("File not found (certificatePath)") } guard net.useCertificateFile(cert: certificatePath) && net.usePrivateKeyFile(cert: certificatePath) && net.checkPrivateKey() else { let code = Int32(net.errorCode()) print("Error validating private key file: (net.errorStr(forCode: code))") return } } }

    The parameter is never used within the function

    opened by enolik97 0
  • Lots of 500s

    Lots of 500s

    I'm using this library to send notifications in batches. I'm creating a single NotificationPusher instance and then using it to send many batches of 100 devices each (please let me know if this is not how the library is meant to be used). Note that I'm doing batching because I don't want my server to be swamped by the app's reaction to the notification, not because of APNS.

    Some batches work fine, returning 100 responses that are either "ok" or "inactive device".

    Most batches reply with a single 500 error response, with no body. Judging by the code this happens when the response count doesn't match the token count inside of the pusher: https://github.com/PerfectlySoft/Perfect-Notifications/blob/master/Sources/PerfectNotifications/NotificationPusher.swift#L531. Sounds like this is being handled like an internal consistency "this should never happen" error, but it happens a lot :)

    What can I do about that? Because this single 500 replaces all responses, I'm not getting the "inactive device" responses. If I keep sending notifications to those tokens, I risk angering APNS. Please help :)

    opened by mipstian 2
  • Refresh APNS Connection

    Refresh APNS Connection

    Hello,

    APNS service has a known. bug that, if you send a request in a session which stays idle for a while, APNS service returns an internal server error such that : "500 Internal Server Error: Unable to write frame"

    Other push services overcome this problem by refreshing their APNS connections when they encounter this kind of a problem. (for example: https://github.com/relayrides/pushy/pull/529)

    Is there a way to refresh connection in Perfect Notifications?

    opened by bisikli 1
Owner
PerfectlySoft Inc.
Server-side Swift
PerfectlySoft Inc.
Apple Push Notifications (APNs) Server-Side library.

Perfect-Notifications 简体中文 APNs remote Notifications for Perfect. This package adds push notification support to your server. Send notifications to iO

PerfectlySoft Inc. 113 Oct 28, 2022
OS X app for sending push with Apple Push Notification service (APNs)

pushHandle OS X app for sending push with Apple Push Notification service (APNs) About This app was created just to allow painless testing of push not

hbk3 3 Nov 17, 2022
Push Hero - pure Swift native macOS application to test push notifications

Dropdowns ❤️ Support my app ❤️ Push Hero - pure Swift native macOS application to test push notifications Quick Access - Organise files in the Mac men

Khoa 307 Oct 17, 2022
The debug application for Apple Push Notification Service (APNs).

Knuff The debug application for Apple Push Notification Service (APNs). Download the latest version Features Send push notifications to APNS (Apple Pu

Knuff 5.2k Dec 26, 2022
OS X and iOS application and framework to play with the Apple Push Notification service (APNs)

Pusher OS X and iOS application and framework to play with the Apple Push Notification service (APNs) Installation Install the Mac app using Homebrew

noodlewerk 6.2k Dec 22, 2022
Swush - macOS Application to play with the Apple Push Notification service (APNs)

Swush ✨ Description A macOS app to push notifications to APNS with ease. ⚡ ?? Pe

Quentin Eude 80 Dec 23, 2022
A SwiftUI iOS App and Vapor Server to send push notifications fueled by Siri Shortcuts.

Puffery An iOS App written in SwiftUI to send push notifications fueled by Siri Shortcuts. You can follow other's channels and directly receive update

Valentin Knabel 29 Oct 17, 2022
PushDispatcher-vapor - Simple Api to dispatch push to APNS with p8 file

PushDispatcher - Vapor The purpose of this application is to facilitate the test

Michel Anderson Lütz Teixeira 3 Oct 18, 2022
'Minimalistic Push' is a minimalistic push-up application now built with Flutter.

Minimalistic Push Minimalistic Push is one of the simplest push-up trackers out there. You can track your push-ups in the training mode and see an ove

Jonas Poxleitner 10 Dec 29, 2022
Push notifications allow developers to reach users, even when users aren't actively using an app!

Push notifications allow developers to reach users, even when users aren't actively using an app! With the latest update of iOS Apple provide very useful extensions which are user-friendly. In this tutorial, I am going to share the configuration, set up of Notification with the media attachments like.

MindInventory 16 Mar 3, 2022
Pushkin is a free open source tool for sending push notifications

Unmaintained This repository is no longer maintained. Pushkin Introduction Pushkin is a free open source tool for sending push notifications. It was d

Nordeus 257 Nov 3, 2022
A simple, reliable and scalable delivery API for transactional push notifications for websites and applications

Catapush is a simple, reliable and scalable delivery API for transactional push notifications for websites and applications. Ideal for sending data-dr

Catapush 0 Dec 29, 2021
A framework for easily testing Push Notifications and Routing in XCUITests

Mussel ?? ?? A framework for easily testing Push Notifications, Universal Links and Routing in XCUITests. As of Xcode 11.4, users are able to test Pus

Compass 65 Dec 28, 2022
Simplifies iOS user permission requests (location, push notifications, camera, contacts, calendar, photos, etc).

ICanHas Swift 4 library that simplifies iOS user permission requests (push notifications, location, camera, photo library, contacts, calendar). Instal

Adolfo Rodriguez 91 Jun 2, 2022
An iOS pre-permissions utility that lets developers ask users on their own dialog for calendar, contacts, location, photos, reminders, twitter, push notifications and more, before making the system-based permission request.

An iOS pre-permissions utility that lets developers ask users on their own dialog for calendar, contacts, location, photos, reminders, twitter, push notifications and more, before making the system-based permission request.

Joe L 420 Dec 22, 2022
⚡️ Capacitor plugin to register push notifications via Azure Notification Hub.

Azure Notification Hubs @jonz94/capacitor-azure-notification-hubs Capacitor plugin to register push notifications via Azure Notification Hub. Install

jonz94 2 Dec 19, 2022
Joseph Miller 0 Jan 7, 2022
Left Side Menu \ Side Bar with modern interface for iOS

SideMenu A customizable, interactive, auto expanding and collapsing side menu fo

Mohammed Albahal 0 Dec 18, 2021
iOS library for device fingerprinting. Does not require server APIs to work, fully client-side operation.

Lightweight iOS library for local device fingerprinting Installation (CocoaPods) # Podfile pod 'FingerprintJS' Note: If you've never used CocoaPods fo

FingerprintJS 45 Dec 17, 2022
A fast, pure swift MongoDB driver based on Swift NIO built for Server Side Swift

A fast, pure swift MongoDB driver based on Swift NIO built for Server Side Swift. It features a great API and a battle-tested core. Supporting both MongoDB in server and embedded environments.

null 646 Dec 10, 2022