Skip to content

Commit b5bd3b3

Browse files
authored
Add semantic safe API for alert notifications (#144)
# Motivation We want to provide new APIs that are semantically safe when sending alerts to APNs. These APIs should feel native in Swift and not leak too many APIs of the APNs interface. # Modification This PR creates a few new semantic types to represent currency types from the APNs API. Furthermore, the PR adds new types for the alert notification and a convenience method to send alert notifications with the APNSClient. # Result We can now send alert notifications.
1 parent 43c55b9 commit b5bd3b3

17 files changed

+1078
-412
lines changed

Sources/APNSwift/APNSAlert.swift

-84
This file was deleted.

Sources/APNSwift/APNSClient.swift

+72
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,78 @@ public final class APNSClient<Decoder: APNSJSONDecoder, Encoder: APNSJSONEncoder
140140
// MARK: - Raw sending
141141

142142
extension APNSClient {
143+
/// Sends a notification to APNs.
144+
///
145+
/// - Important: This method exposes the raw API for APNs. In general, this should be avoided
146+
/// and the semantic-safe APIs should be used instead.
147+
///
148+
/// - Parameters:
149+
/// - payload: The notification payload.
150+
///
151+
/// - deviceToken: The hexadecimal bytes that identify the user’s device. Your app receives the bytes for this device token
152+
/// when registering for remote notifications.
153+
///
154+
/// - pushType: The value of this header must accurately reflect the contents of your notification’s payload. If there’s a mismatch,
155+
/// or if the header is missing on required systems, APNs may return an error, delay the delivery of the notification, or drop it altogether.
156+
///
157+
/// - apnsID: A canonical UUID that identifies the notification. If there is an error sending the notification,
158+
/// APNs uses this value to identify the notification to your server. The canonical form is 32 lowercase hexadecimal digits,
159+
/// displayed in five groups separated by hyphens in the form 8-4-4-4-12. An example UUID is as follows: 123e4567-e89b-12d3-a456-42665544000.
160+
/// If you omit this, a new UUID is created by APNs and returned in the response.
161+
///
162+
/// - expiration: The date when the notification is no longer valid and can be discarded. If this value is not `none`,
163+
/// APNs stores the notification and tries to deliver it at least once, repeating the attempt as needed if it is unable to deliver the notification the first time.
164+
/// If the value is `immediately`, APNs treats the notification as if it expires immediately and does not store the notification or attempt to redeliver it.
165+
///
166+
/// - priority: The priority of the notification. If you omit this header, APNs sets the notification priority to `immediately`.
167+
///
168+
/// - topic: The topic for the notification. In general, the topic is your app’s bundle ID/app ID.
169+
/// It can have a suffix based on the type of push notification. If you’re using a certificate that supports PushKit VoIP or watchOS complication notifications,
170+
/// you must include this header with bundle ID of you app and if applicable, the proper suffix.
171+
/// If you’re using token-based authentication with APNs, you must include this header with the correct bundle ID and suffix combination.
172+
///
173+
/// - collapseID: An identifier you use to coalesce multiple notifications into a single notification for the user.
174+
/// Typically, each notification request causes a new notification to be displayed on the user’s device.
175+
/// When sending the same notification more than once, use the same value in this header to coalesce the requests.
176+
/// The value of this key must not exceed 64 bytes.
177+
///
178+
/// - deadline: Point in time by which sending the notification to APNs must complete.
179+
///
180+
/// - logger: The logger to use for sending this notification.
181+
@discardableResult
182+
@inlinable
183+
public func send<Payload: Encodable>(
184+
payload: Payload?,
185+
deviceToken: String,
186+
pushType: APNSPushType,
187+
apnsID: UUID? = nil,
188+
expiration: APNSNotificationExpiration,
189+
priority: APNSPriority,
190+
topic: String? = nil,
191+
collapseID: String? = nil,
192+
deadline: NIODeadline,
193+
logger: Logger = _noOpLogger
194+
) async throws -> APNSResponse {
195+
var byteBuffer = self.byteBufferAllocator.buffer(capacity: 0)
196+
197+
if let payload = payload {
198+
try self.requestEncoder.encode(payload, into: &byteBuffer)
199+
}
200+
201+
return try await self.send(
202+
payload: byteBuffer,
203+
deviceToken: deviceToken,
204+
pushType: pushType.configuration.rawValue,
205+
apnsID: apnsID,
206+
expiration: expiration.expiration,
207+
priority: priority.rawValue,
208+
topic: topic,
209+
collapseID: collapseID,
210+
deadline: deadline,
211+
logger: logger
212+
)
213+
}
214+
143215
/// Sends a notification to APNs.
144216
///
145217
/// - Important: This method exposes the raw API for APNs. In general, this should be avoided

Sources/APNSwift/APNSNotification.swift

-18
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the APNSwift open source project
4+
//
5+
// Copyright (c) 2022 the APNSwift project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of APNSwift project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
/// A struct representing the different expiration options for a notification.
16+
public struct APNSNotificationExpiration: Hashable {
17+
/// The date at which the notification is no longer valid.
18+
/// This value is a UNIX epoch expressed in seconds (UTC)
19+
@usableFromInline
20+
let expiration: Int?
21+
22+
/// Omits sending an expiration for APNs. APNs will default to a default value.
23+
public static let none = Self(expiration: nil)
24+
25+
/// This tells APNs to not try to redeliver the notification.
26+
///
27+
/// - Important: This does not mean that the notification is delivered immediately. Due to various network conditions
28+
/// the message might be delivered with some delay.
29+
public static let immediately = Self(expiration: 0)
30+
31+
/// This tells APNs that the notification expires at the given date.
32+
///
33+
/// - Important: This does not mean that the notification is delivered until this date. Due to various network conditions
34+
/// the message might be delivered after the passed date.
35+
public static func timeIntervalSince1970InSeconds(_ timeInterval: Int) -> Self {
36+
Self(expiration: timeInterval)
37+
}
38+
}

Sources/APNSwift/APNSPayload.swift

-99
This file was deleted.

Sources/APNSwift/APNSPriority.swift

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the APNSwift open source project
4+
//
5+
// Copyright (c) 2022 the APNSwift project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of APNSwift project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
/// A struct which represents the supported priorities by APNs.
16+
public struct APNSPriority: Hashable {
17+
/// The underlying raw value that is send to APNs.
18+
@usableFromInline
19+
internal let rawValue: Int
20+
21+
/// Specifies that the notification should be send immediately.
22+
public static let immediately = Self(rawValue: 10)
23+
24+
/// Specifies that the notification should be send based on power considerations on the user’s device.
25+
public static let consideringDevicePower = Self(rawValue: 5)
26+
}

0 commit comments

Comments
 (0)