Skip to content

Commit

Permalink
Migrated to new swift concurrency
Browse files Browse the repository at this point in the history
  • Loading branch information
polyitan committed Jun 28, 2022
1 parent 143a84e commit f5e48fb
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 136 deletions.
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
// swift-tools-version:5.3
// swift-tools-version:5.6

import PackageDescription

let package = Package(
name: "SwiftyAPNS",
platforms: [
.iOS(.v12),
.macOS(.v10_13)
.iOS(.v13),
.macOS(.v12)
],
products: [
.library(
Expand Down
14 changes: 4 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,12 @@ let notification = APNSNotification.init(payload: <#Notification Payload#>,
The values in responses can be handled asynchronously.

```swift
provider.push(notification) { (result) in
switch(result) {
case .success(let responce):
if let error = responce.reason {
// Push Notification failure
} else {
// Push Notification was successfully sent
}
case .failure(let error):
do {
let responce = try await provider.push(notification)
// Push Notification was successfully sent
} catch {
// Push Notification failure
}
}
```

### [More examples](/Tests/SwiftyAPNSTests/SwiftyAPNSTests.swift)
Expand Down
39 changes: 13 additions & 26 deletions Sources/SwiftyAPNS/Provider/CertificateProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,39 +11,26 @@ import Foundation
internal final class APNSCertificateProvider: NSObject, APNSSendMessageProtocol {

private var identity: SecIdentity
private var sesion: URLSession = URLSession.shared
private var session: URLSession = URLSession.shared

private static let decoder = JSONDecoder()

public init(identity: SecIdentity, sandbox: Bool = true, configuration: URLSessionConfiguration = URLSessionConfiguration.default, qeue: OperationQueue = OperationQueue.main) {
public init(identity: SecIdentity, sandbox: Bool = true, configuration: URLSessionConfiguration = URLSessionConfiguration.default) {
self.identity = identity
super.init()
self.sesion = URLSession.init(configuration: configuration, delegate: self, delegateQueue: qeue)
self.session = URLSession.init(configuration: configuration, delegate: self, delegateQueue: nil)
}

public func push<P: Payloadable>(_ notification: APNSNotification<P>, completion: @escaping (Result<APNSResponse, Error>) -> Void) {
do {
let request = try APNSRequestFactory.makeRequest(notification)
let task = self.sesion.dataTask(with: request) { (data, responce, error) in
if let error = error {
completion(.failure(error))
} else if let responce = responce as? HTTPURLResponse, let data = data {
if let apnsStatus = APNSStatus(code: responce.statusCode),
let apnsId = responce.allHeaderFields["apns-id"] as? String
{
let reason = try? Self.decoder.decode(APNSError.self, from: data)
let apnsResponce = APNSResponse(status: apnsStatus, apnsId: apnsId, reason: reason)
completion(.success(apnsResponce))
} else {
completion(.failure(APNSProviderError.parseResponce))
}
} else {
completion(.failure(APNSProviderError.emptyData))
}
}
task.resume()
} catch {
completion(.failure(error))
public func push<P: Payloadable>(_ notification: APNSNotification<P>) async throws -> APNSResponse {
let request = try APNSRequestFactory.makeRequest(notification)
let (data, response) = try await session.data(for: request)
if let responce = response as? HTTPURLResponse,
let apnsStatus = APNSStatus(code: responce.statusCode),
let apnsId = responce.allHeaderFields["apns-id"] as? String {
let reason = try? Self.decoder.decode(APNSError.self, from: data)
return APNSResponse(status: apnsStatus, apnsId: apnsId, reason: reason)
} else {
throw APNSProviderError.parseResponce
}
}
}
Expand Down
47 changes: 16 additions & 31 deletions Sources/SwiftyAPNS/Provider/KeyProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,30 @@ import Foundation
internal final class APNSKeyProvider: APNSSendMessageProtocol {

private let token: APNSBearerToken
private let sesion: URLSession
private let session: URLSession

private static let encoder = JSONEncoder()
private static let decoder = JSONDecoder()

public init(p8: P8, keyId: String, teamId: String, sandbox: Bool = true,
configuration: URLSessionConfiguration = URLSessionConfiguration.default,
qeue: OperationQueue = OperationQueue.main)
configuration: URLSessionConfiguration = URLSessionConfiguration.default)
{
self.token = APNSBearerToken(p8: p8, keyId: keyId, teamId: teamId)
self.sesion = URLSession.init(configuration: configuration, delegate: nil, delegateQueue: qeue)
self.session = URLSession.init(configuration: configuration)
}

public func push<P: Payloadable>(_ notification: APNSNotification<P>, completion: @escaping (Result<APNSResponse, Error>) -> Void) {
do {
var request = try APNSRequestFactory.makeRequest(notification)
let dataToken = try token.generateIfExpired()
request.setValue("application/json;", forHTTPHeaderField: "Content-Type")
request.setValue("bearer \(dataToken)", forHTTPHeaderField: "Authorization")
let task = self.sesion.dataTask(with: request) { (data, responce, error) in
if let error = error {
completion(.failure(error))
} else if let responce = responce as? HTTPURLResponse, let data = data {
if let apnsStatus = APNSStatus(code: responce.statusCode),
let apnsId = responce.allHeaderFields["apns-id"] as? String
{
let reason = try? Self.decoder.decode(APNSError.self, from: data)
let apnsResponce = APNSResponse(status: apnsStatus, apnsId: apnsId, reason: reason)
completion(.success(apnsResponce))
} else {
completion(.failure(APNSProviderError.parseResponce))
}
} else {
completion(.failure(APNSProviderError.emptyData))
}
}
task.resume()
} catch {
completion(.failure(error))
public func push<P: Payloadable>(_ notification: APNSNotification<P>) async throws -> APNSResponse {
var request = try APNSRequestFactory.makeRequest(notification)
let dataToken = try token.generateIfExpired()
request.setValue("application/json;", forHTTPHeaderField: "Content-Type")
request.setValue("bearer \(dataToken)", forHTTPHeaderField: "Authorization")
let (data, response) = try await session.data(for: request)
if let responce = response as? HTTPURLResponse,
let apnsStatus = APNSStatus(code: responce.statusCode),
let apnsId = responce.allHeaderFields["apns-id"] as? String {
let reason = try? Self.decoder.decode(APNSError.self, from: data)
return APNSResponse(status: apnsStatus, apnsId: apnsId, reason: reason)
} else {
throw APNSProviderError.parseResponce
}
}
}
14 changes: 6 additions & 8 deletions Sources/SwiftyAPNS/Provider/Provider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,21 @@ import Foundation
public struct APNSProvider {
private let provider: APNSSendMessageProtocol

public func push<P: Payloadable>(_ notification: APNSNotification<P>, completion: @escaping (Result<APNSResponse, Error>) -> Void) {
self.provider.push(notification, completion: completion)
public func push<P: Payloadable>(_ notification: APNSNotification<P>) async throws -> APNSResponse {
try await self.provider.push(notification)
}
}

extension APNSProvider {
public init(identity: SecIdentity, sandbox: Bool = true,
configuration: URLSessionConfiguration = URLSessionConfiguration.default,
qeue: OperationQueue = OperationQueue.main)
configuration: URLSessionConfiguration = URLSessionConfiguration.default)
{
self.provider = APNSCertificateProvider(identity: identity, sandbox: sandbox, configuration: configuration, qeue: qeue)
self.provider = APNSCertificateProvider(identity: identity, sandbox: sandbox, configuration: configuration)
}

public init(p8: P8, keyId: String, teamId: String, sandbox: Bool = true,
configuration: URLSessionConfiguration = URLSessionConfiguration.default,
qeue: OperationQueue = OperationQueue.main)
configuration: URLSessionConfiguration = URLSessionConfiguration.default)
{
self.provider = APNSKeyProvider(p8: p8, keyId: keyId, teamId: teamId, sandbox: sandbox, configuration: configuration, qeue: qeue)
self.provider = APNSKeyProvider(p8: p8, keyId: keyId, teamId: teamId, sandbox: sandbox, configuration: configuration)
}
}
2 changes: 1 addition & 1 deletion Sources/SwiftyAPNS/Provider/SendMessageProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
//

internal protocol APNSSendMessageProtocol {
func push<P: Payloadable>(_ notification: APNSNotification<P>, completion: @escaping (Result<APNSResponse, Error>) -> Void)
func push<P: Payloadable>(_ notification: APNSNotification<P>) async throws -> APNSResponse
}
36 changes: 6 additions & 30 deletions Tests/SwiftyAPNSTests/SwiftyAPNSTests+Private.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,23 @@ import XCTest
@testable import SwiftyAPNS

extension SwiftyAPNSTests {
func sendPushNotification<P: Payloadable>(_ notification: APNSNotification<P>) {
func sendPushNotification<P: Payloadable>(_ notification: APNSNotification<P>) async throws {
#if false
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
let encoded = try! encoder.encode(notification.payload)
print("Payload:\n\(String(data: encoded, encoding: .utf8)!)")
#endif
let expect = self.expectation(description: "APNSExpectation")
provider.push(notification) { (result) in
switch(result) {
case .success(let responce):
if let error = responce.reason {
XCTFail(error.errorDescription ?? "Failure send push notification")
} else {
print("ApnsId: \(responce.apnsId)")
expect.fulfill()
}
case .failure(let error):
if let error = error as? LocalizedError {
XCTFail(error.localizedDescription)
} else {
XCTFail("Failure send push notification")
}
}
}
}

func waitForResponce() {
self.waitForExpectations(timeout: 30.0) { (error) in
if let error = error {
XCTFail(error.localizedDescription)
}
}
let responce = try await provider.push(notification)
XCTAssertNil(responce.reason)
}

func visit(notification: Notification) {
func visit(notification: Notification) async throws {
switch notification {
case .payload(let notificatiuon):
sendPushNotification(notificatiuon)
try await sendPushNotification(notificatiuon)
case .payload4(let notificatiuon):
sendPushNotification(notificatiuon)
try await sendPushNotification(notificatiuon)
}
}

Expand Down
47 changes: 20 additions & 27 deletions Tests/SwiftyAPNSTests/SwiftyAPNSTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -116,56 +116,49 @@ final class SwiftyAPNSTests: XCTestCase {
#endif
}

func testAlertPushExample() {
sendPushNotification(alertPushExample)
waitForResponce()
func testAlertPushExample() async throws {
try await sendPushNotification(alertPushExample)
}

func testAlertWithSubtitlePushExample() {
sendPushNotification(alertWithSubtitlePushExample)
waitForResponce()
func testAlertWithSubtitlePushExample() async throws {
try await sendPushNotification(alertWithSubtitlePushExample)
}

func testLocalizableAlertPushExample() {
sendPushNotification(localizableAlertPushExample)
waitForResponce()
func testLocalizableAlertPushExample() async throws {
try await sendPushNotification(localizableAlertPushExample)
}

func testAlertWithCustomActionsPushExample() {
sendPushNotification(alertWithCustomActionsPushExample)
waitForResponce()
func testAlertWithCustomActionsPushExample() async throws {
try await sendPushNotification(alertWithCustomActionsPushExample)
}

func testLocalizableAlertPushWithCustomPayloadExample1() {
sendPushNotification(localizableAlertPushWithCustomPayloadExample1)
waitForResponce()
func testLocalizableAlertPushWithCustomPayloadExample1() async throws {
try await sendPushNotification(localizableAlertPushWithCustomPayloadExample1)
}

func testLocalizableAlertPushWithCustomPayloadExample2() {
sendPushNotification(localizableAlertPushWithCustomPayloadExample2)
waitForResponce()
func testLocalizableAlertPushWithCustomPayloadExample2() async throws {
try await sendPushNotification(localizableAlertPushWithCustomPayloadExample2)
}

func testModifyingContentPushExample() {
sendPushNotification(modifyingContentPushExample)
waitForResponce()
func testModifyingContentPushExample() async throws {
try await sendPushNotification(modifyingContentPushExample)
}

func testBackgroundPushExample() {
sendPushNotification(backgroundPushExample)
waitForResponce()
func testBackgroundPushExample() async throws {
try await sendPushNotification(backgroundPushExample)
}

func testSendingMultiplePushes() {
func testSendingMultiplePushes() async throws {
let notifications: [Notification] = [
.payload(notificatiuon: alertPushExample),
.payload(notificatiuon: alertWithSubtitlePushExample),
.payload(notificatiuon: localizableAlertPushExample),
.payload(notificatiuon: alertWithCustomActionsPushExample),
.payload4(notificatiuon: backgroundPushExample)
]
notifications.forEach(visit)
waitForResponce()
for notification in notifications {
try await visit(notification: notification)
}
}

static var allTests = [
Expand Down

0 comments on commit f5e48fb

Please sign in to comment.