{"id":13465974,"url":"https://github.com/PerfectlySoft/Perfect-Notifications","last_synced_at":"2025-03-25T21:30:57.586Z","repository":{"id":63920172,"uuid":"61678525","full_name":"PerfectlySoft/Perfect-Notifications","owner":"PerfectlySoft","description":"Apple Push Notifications (APNs) Server-Side library.","archived":false,"fork":false,"pushed_at":"2020-06-01T20:43:50.000Z","size":91,"stargazers_count":116,"open_issues_count":8,"forks_count":30,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-03-22T22:05:27.779Z","etag":null,"topics":["ios","ios-notifications","perfect","server-side-swift","swift"],"latest_commit_sha":null,"homepage":"https://www.perfect.org","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PerfectlySoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-06-22T01:15:58.000Z","updated_at":"2024-12-26T10:03:11.000Z","dependencies_parsed_at":"2022-11-29T10:45:32.316Z","dependency_job_id":null,"html_url":"https://github.com/PerfectlySoft/Perfect-Notifications","commit_stats":null,"previous_names":[],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerfectlySoft%2FPerfect-Notifications","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerfectlySoft%2FPerfect-Notifications/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerfectlySoft%2FPerfect-Notifications/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PerfectlySoft%2FPerfect-Notifications/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PerfectlySoft","download_url":"https://codeload.github.com/PerfectlySoft/Perfect-Notifications/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245547060,"owners_count":20633283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","ios-notifications","perfect","server-side-swift","swift"],"created_at":"2024-07-31T15:00:37.544Z","updated_at":"2025-03-25T21:30:57.280Z","avatar_url":"https://github.com/PerfectlySoft.png","language":"Swift","funding_links":[],"categories":["Libs","Network [🔝](#readme)","Server Side Utilities"],"sub_categories":["Network","iOS Notifications"],"readme":"# Perfect-Notifications [简体中文](README.zh_CN.md)\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"http://perfect.org/get-involved.html\" target=\"_blank\"\u003e\n        \u003cimg src=\"http://perfect.org/assets/github/perfect_github_2_0_0.jpg\" alt=\"Get Involed with Perfect!\" width=\"854\" /\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://developer.apple.com/swift/\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/Swift-5.2-orange.svg?style=flat\" alt=\"Swift 5.2\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://developer.apple.com/swift/\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/Platforms-macOS%20%7C%20Linux%20-lightgray.svg?style=flat\" alt=\"Platforms OS X | Linux\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"http://perfect.org/licensing.html\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://img.shields.io/badge/License-Apache-lightgrey.svg?style=flat\" alt=\"License Apache\"\u003e\n    \u003c/a\u003e\n\u003c/p\u003e\n\nAPNs remote Notifications for Perfect. This package adds push notification support to your server. Send notifications to iOS/macOS devices.\n\nBuilding\n--------\n\nThis is a Swift Package manager based project. Add this repository as a dependency in your Package.swift file.\n\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n.package(url:\"https://github.com/PerfectlySoft/Perfect-Notifications.git\", from: \"5.0.0\")\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOverview\n--------\n\nThis 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.\n\nWhen 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.\n\nObtain APNs Auth Key\n--------\n\nTo 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 \u0026amp; Profiles\" from the menu. Then, under \"Keys\", choose \"All\".\n\nIf 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.\n\nClick \"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.\n\nFinally 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.\n\nServer Configuration\n------\n\nTo send notifications from your server your must have three pieces of information:\n\n1. The private key file which was downloaded\n2. The 10 character key id\n3. Your 10 character team id\n4. An iOS/macOS app id\n\nThese 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.\n\nIn 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.\n\n```swift\nimport PerfectNotifications\n\n// your app id. we use this as the configuration name, but they do not have to match\nlet notificationsAppId = \"my.app.id\"\n\nlet apnsKeyIdentifier = \"AB90CD56XY\"\nlet apnsTeamIdentifier = \"YX65DC09BA\"\nlet apnsPrivateKeyFilePath = \"./APNsAuthKey_AB90CD56XY.p8\"\n\nNotificationPusher.addConfigurationAPNS(\n\tname: notificationsTestId, \n\tproduction: false, // should be false when running pre-release app in debugger\n\tkeyId: apnsKeyIdentifier, \n\tteamId: apnsTeamIdentifier, \n\tprivateKeyPath: apnsPrivateKeyFilePath)\n```\n\nAfter 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:\n\n```swift\nlet deviceIds: [String] = [...]\nlet n = NotificationPusher(apnsTopic: notificationsTestId)\nn.pushAPNS(\n\tconfigurationName: notificationsTestId, \n\tdeviceTokens: deviceIds, \n\tnotificationItems: [.alertBody(\"Hello!\"), .sound(\"default\")]) {\n\t\tresponses in\n\t\tprint(\"\\(responses)\")\n\t\t...\n}\n```\n\nThe 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.\n\nPublic API\n----\n\nThe full public version 3.0 API for notification pusher follows:\n\n```swift\npublic class NotificationPusher {\n\t\n\t/// Add an APNS configuration which can be later used to push notifications.\n\tpublic static func addConfigurationAPNS(\n\t\tname: String, \n\t\tproduction: Bool, \n\t\tkeyId: String, \n\t\tteamId: String, \n\t\tprivateKeyPath: String)\n\n\t/// Initialize given an apns-topic string.\n\tpublic init(\n\t\tapnsTopic: String,\n\t\texpiration: APNSExpiration = .immediate,\n\t\tpriority: APNSPriority = .immediate,\n\t\tcollapseId: String? = nil)\n\t\t\n\t/// Push one message to one device.\n\t/// Provide the previously set configuration name, device token.\n\t/// Provide a list of APNSNotificationItems.\n\t/// Provide a callback with which to receive the response.\n\tpublic func pushAPNS(\n\t\tconfigurationName: String, \n\t\tdeviceToken: String, \n\t\tnotificationItems: [APNSNotificationItem], \n\t\tcallback: @escaping (NotificationResponse) -\u003e ())\n\t\n\t/// Push one message to multiple devices.\n\t/// Provide the previously set configuration name, and zero or more device tokens. The same message will be sent to each device.\n\t/// Provide a list of APNSNotificationItems.\n\t/// Provide a callback with which to receive the responses.\n\tpublic func pushAPNS(\n\t\tconfigurationName: String, deviceTokens: [String],\n\t\tnotificationItems: [APNSNotificationItem],\n\t\tcallback: @escaping ([NotificationResponse]) -\u003e ())\n}\n```\n\nThe remaining structures, including APNSNotificationItem follow:\n\n```swift\n/// Items to configure an individual notification push.\npublic enum APNSNotificationItem {\n    /// alert body child property\n\tcase alertBody(String)\n    /// alert title child property\n\tcase alertTitle(String)\n    /// alert title-loc-key\n\tcase alertTitleLoc(String, [String]?)\n    /// alert action-loc-key\n\tcase alertActionLoc(String)\n    /// alert loc-key\n\tcase alertLoc(String, [String]?)\n    /// alert launch-image\n\tcase alertLaunchImage(String)\n    /// aps badge key\n\tcase badge(Int)\n    /// aps sound key\n\tcase sound(String)\n    /// aps content-available key\n\tcase contentAvailable\n\t/// aps category key\n\tcase category(String)\n\t/// aps thread-id key\n\tcase threadId(String)\n    /// custom payload data\n\tcase customPayload(String, Any)\n    /// apn mutable-content key\n\tcase mutableContent\n}\n\npublic enum APNSPriority: Int {\n\tcase immediate = 10\n\tcase background = 5\n}\n\n/// Time in the future when the notification, if has not be able to be delivered, will expire.\npublic enum APNSExpiration {\n\t/// Discard the notification if it can't be immediately delivered.\n\tcase immediate\n\t/// now + seconds\n\tcase relative(Int)\n\t/// absolute UTC time since epoch\n\tcase absolute(Int)\n}\n\n/// The response object given after a push attempt.\npublic struct NotificationResponse: CustomStringConvertible {\n\t/// The response code for the request.\n\tpublic let status: HTTPResponseStatus\n\t/// The response body data bytes.\n\tpublic let body: [UInt8]\n\t/// The body data bytes interpreted as JSON and decoded into a Dictionary.\n\tpublic var jsonObjectBody: [String:Any]\n\t/// The body data bytes converted to String.\n\tpublic var stringBody: String\n\tpublic var description: String\n}\n```\n\nAdditional Notes\n----\n\nAPNs 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.\n\nConsult [Perfect-NotificationsExample](https://github.com/PerfectExamples/Perfect-NotificationsExample) for a client/server combination which can be easily configured with your own information to quickly get APNS notifications for your apps.\n\n## Further Information\nFor more information on the Perfect project, please visit [perfect.org](http://perfect.org).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPerfectlySoft%2FPerfect-Notifications","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPerfectlySoft%2FPerfect-Notifications","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPerfectlySoft%2FPerfect-Notifications/lists"}