Skip to content

Commit

Permalink
Merge pull request #562 from bizz84/develop
Browse files Browse the repository at this point in the history
0.16.1, watchOS and SPM fixes
  • Loading branch information
Sam-Spencer authored Jul 19, 2020
2 parents 7c83154 + dfe5002 commit 9974acf
Show file tree
Hide file tree
Showing 38 changed files with 372 additions and 302 deletions.
21 changes: 16 additions & 5 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
// swift-tools-version:4.2
// swift-tools-version:5.0
import PackageDescription

let package = Package(
name: "SwiftyStoreKit",
// platforms: [.iOS("8.0"), .macOS("10.10"), tvOS("9.0"), .watchOS("2.0")],
platforms: [.iOS("8.0"), .macOS("10.10"), .tvOS("9.0"), .watchOS("6.2")],
products: [
.library(name: "SwiftyStoreKit", targets: ["SwiftyStoreKit"])
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "SwiftyStoreKit",
targets: ["SwiftyStoreKit"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target(
name: "SwiftyStoreKit",
path: "SwiftyStoreKit"
)
dependencies: []),
.testTarget(
name: "SwiftyStoreKitTests",
dependencies: ["SwiftyStoreKit"]),
]
)
File renamed without changes.
File renamed without changes.
18 changes: 13 additions & 5 deletions SwiftyStoreKit/OS.swift → Sources/SwiftyStoreKit/OS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,22 @@ import StoreKit
#endif

// MARK: - Missing SKError on watchOS
#if os(watchOS)
#if os(watchOS) && swift(<5.3)
public struct SKError: Error {

var Code: SKErrorCode = .unknown
var _nsError: NSError?
public typealias Code = SKErrorCode

static var unknown: SKErrorCode = .unknown
static var paymentInvalid: SKErrorCode = .paymentInvalid
let _nsError: NSError

init(_nsError: NSError) {
self._nsError = _nsError
}

var code: Code {
return Code(rawValue: _nsError.code) ?? .unknown
}

static var unknown: Code = .unknown
static var paymentInvalid: Code = .paymentInvalid
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import Foundation
import StoreKit

protocol TransactionController {

/// Process the supplied transactions on a given queue.
/// - parameter transactions: transactions to process
/// - parameter paymentQueue: payment queue for finishing transactions
Expand All @@ -41,40 +41,42 @@ public enum TransactionResult {
}

public protocol PaymentQueue: class {

func add(_ observer: SKPaymentTransactionObserver)
func remove(_ observer: SKPaymentTransactionObserver)

func add(_ payment: SKPayment)

func start(_ downloads: [SKDownload])
func pause(_ downloads: [SKDownload])
#if os(watchOS)
func resumeDownloads(_ downloads: [SKDownload])
#else
func resume(_ downloads: [SKDownload])
#endif
func cancel(_ downloads: [SKDownload])

func restoreCompletedTransactions(withApplicationUsername username: String?)

func finishTransaction(_ transaction: SKPaymentTransaction)
}

extension SKPaymentQueue: PaymentQueue { }
extension SKPaymentQueue: PaymentQueue {
#if os(watchOS) && swift(<5.3)
public func resume(_ downloads: [SKDownload]) {
resumeDownloads(downloads)
}
#endif
}

extension SKPaymentTransaction {

open override var debugDescription: String {
let transactionId = transactionIdentifier ?? "null"
return "productId: \(payment.productIdentifier), transactionId: \(transactionId), state: \(transactionState), date: \(String(describing: transactionDate))"
}
}

extension SKPaymentTransactionState: CustomDebugStringConvertible {

public var debugDescription: String {

switch self {
case .purchasing: return "purchasing"
case .purchased: return "purchased"
Expand All @@ -87,24 +89,24 @@ extension SKPaymentTransactionState: CustomDebugStringConvertible {
}

class PaymentQueueController: NSObject, SKPaymentTransactionObserver {

private let paymentsController: PaymentsController

private let restorePurchasesController: RestorePurchasesController

private let completeTransactionsController: CompleteTransactionsController

unowned let paymentQueue: PaymentQueue

deinit {
paymentQueue.remove(self)
}

init(paymentQueue: PaymentQueue = SKPaymentQueue.default(),
paymentsController: PaymentsController = PaymentsController(),
restorePurchasesController: RestorePurchasesController = RestorePurchasesController(),
completeTransactionsController: CompleteTransactionsController = CompleteTransactionsController()) {

self.paymentQueue = paymentQueue
self.paymentsController = paymentsController
self.restorePurchasesController = restorePurchasesController
Expand All @@ -118,53 +120,53 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
let message = "SwiftyStoreKit.completeTransactions() must be called when the app launches."
assert(completeTransactionsController.completeTransactions != nil, message)
}

func startPayment(_ payment: Payment) {
assertCompleteTransactionsWasCalled()

let skPayment = SKMutablePayment(product: payment.product)
skPayment.applicationUsername = payment.applicationUsername
skPayment.quantity = payment.quantity

if #available(iOS 12.2, tvOS 12.2, OSX 10.14.4, *) {
if #available(iOS 12.2, tvOS 12.2, OSX 10.14.4, watchOS 6.2, *) {
if let discount = payment.paymentDiscount?.discount as? SKPaymentDiscount {
skPayment.paymentDiscount = discount
}
}

#if os(iOS) || os(tvOS)
if #available(iOS 8.3, *) {
#if os(iOS) || os(tvOS) || os(watchOS)
if #available(iOS 8.3, watchOS 6.2, *) {
skPayment.simulatesAskToBuyInSandbox = payment.simulatesAskToBuyInSandbox
}
#endif

#endif
paymentQueue.add(skPayment)

paymentsController.append(payment)
}

func restorePurchases(_ restorePurchases: RestorePurchases) {
assertCompleteTransactionsWasCalled()

if restorePurchasesController.restorePurchases != nil {
return
}

paymentQueue.restoreCompletedTransactions(withApplicationUsername: restorePurchases.applicationUsername)

restorePurchasesController.restorePurchases = restorePurchases
}

func completeTransactions(_ completeTransactions: CompleteTransactions) {

guard completeTransactionsController.completeTransactions == nil else {
print("SwiftyStoreKit.completeTransactions() should only be called once when the app launches. Ignoring this call")
return
}

completeTransactionsController.completeTransactions = completeTransactions
}

func finishTransaction(_ transaction: PaymentTransaction) {
guard let skTransaction = transaction as? SKPaymentTransaction else {
print("Object is not a SKPaymentTransaction: \(transaction)")
Expand All @@ -181,22 +183,18 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
}

func resume(_ downloads: [SKDownload]) {
#if os(watchOS)
paymentQueue.resumeDownloads(downloads)
#else
paymentQueue.resume(downloads)
#endif
}
func cancel(_ downloads: [SKDownload]) {
paymentQueue.cancel(downloads)
}

var shouldAddStorePaymentHandler: ShouldAddStorePaymentHandler?
var updatedDownloadsHandler: UpdatedDownloadsHandler?

// MARK: SKPaymentTransactionObserver
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {

/*
* Some notes about how requests are processed by SKPaymentQueue:
*
Expand All @@ -221,39 +219,39 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
var unhandledTransactions = transactions.filter { $0.transactionState != .purchasing }

if unhandledTransactions.count > 0 {

unhandledTransactions = paymentsController.processTransactions(transactions, on: paymentQueue)

unhandledTransactions = restorePurchasesController.processTransactions(unhandledTransactions, on: paymentQueue)

unhandledTransactions = completeTransactionsController.processTransactions(unhandledTransactions, on: paymentQueue)

if unhandledTransactions.count > 0 {
let strings = unhandledTransactions.map { $0.debugDescription }.joined(separator: "\n")
print("unhandledTransactions:\n\(strings)")
}
}
}

func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) {

}

func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {

restorePurchasesController.restoreCompletedTransactionsFailed(withError: error)
}

func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {

restorePurchasesController.restoreCompletedTransactionsFinished()
}

func paymentQueue(_ queue: SKPaymentQueue, updatedDownloads downloads: [SKDownload]) {

updatedDownloadsHandler?(downloads)
}

#if os(iOS) && !targetEnvironment(macCatalyst)
func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -118,17 +118,10 @@ public class SwiftyStoreKit {
return RestoreResults(restoredPurchases: restoredPurchases, restoreFailedPurchases: restoreFailedPurchases)
}

#if os(watchOS)
private func storeInternalError(code: SKErrorCode = SKErrorCode.unknown, description: String = "") -> SKError {
let error = NSError(domain: SKErrorDomain, code: code.rawValue, userInfo: [ NSLocalizedDescriptionKey: description ])
return SKError.init(Code: code, _nsError: error)
}
#else
private func storeInternalError(code: SKError.Code = SKError.unknown, description: String = "") -> SKError {
let error = NSError(domain: SKErrorDomain, code: code.rawValue, userInfo: [ NSLocalizedDescriptionKey: description ])
return SKError(_nsError: error)
}
#endif
}

extension SwiftyStoreKit {
Expand Down
Loading

0 comments on commit 9974acf

Please sign in to comment.