Skip to content

Commit 8fa93ef

Browse files
authored
Merge pull request #610 from bizz84/develop
Some Bug Fixes & Improvements
2 parents c4658da + 70761d2 commit 8fa93ef

22 files changed

+160
-96
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
All notable changes to this project will be documented in this file.
44

5+
* Make `ProductsInfoController`'s `retrieveProductsInfo` thread safe ([#405]https://github.com/bizz84/SwiftyStoreKit/pull/495), related issues: [#344](https://github.com/bizz84/SwiftyStoreKit/issues/344) and [#468](https://github.com/bizz84/SwiftyStoreKit/issues/468)
6+
57
## [0.15.0](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.15.0) Update project to Swift 5, Xcode 10.2
68

79
* Update project to Swift 5 ([#457](https://github.com/bizz84/SwiftyStoreKit/pull/457)), related issue: [#456](https://github.com/bizz84/SwiftyStoreKit/issues/456)

Package.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ let package = Package(
88
// Products define the executables and libraries produced by a package, and make them visible to other packages.
99
.library(
1010
name: "SwiftyStoreKit",
11-
targets: ["SwiftyStoreKit"]),
11+
targets: ["SwiftyStoreKit"])
1212
],
1313
dependencies: [
1414
// Dependencies declare other packages that this package depends on.
@@ -22,6 +22,6 @@ let package = Package(
2222
dependencies: []),
2323
.testTarget(
2424
name: "SwiftyStoreKitTests",
25-
dependencies: ["SwiftyStoreKit"]),
25+
dependencies: ["SwiftyStoreKit"])
2626
]
2727
)

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,8 @@ It would be great to showcase apps using SwiftyStoreKit here. Pull requests welc
798798
* [Talk Dim Sum](https://itunes.apple.com/us/app/talk-dim-sum/id953929066) - Your dim sum companion
799799
* [Sluggard](https://itunes.apple.com/app/id1160131071) - Perform simple exercises to reduce the risks of sedentary lifestyle
800800
* [Debts iOS](https://debts.ivanvorobei.by/ios) & [Debts macOS](https://debts.ivanvorobei.by/macos) - Track amounts owed
801+
* [Botcher](https://itunes.apple.com/us/app/id1522337788) - Good for finding something to do
802+
* [Hashr](https://apps.apple.com/app/id1166499829) - Generate unique password hashes based on website and master password
801803

802804
A full list of apps is published [on AppSight](https://www.appsight.io/sdk/574154).
803805

Sources/SwiftyStoreKit/InAppProductQueryRequest.swift

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,20 @@ public protocol InAppRequest: class {
3131
func cancel()
3232
}
3333

34-
protocol InAppProductRequest: InAppRequest { }
34+
protocol InAppProductRequest: InAppRequest {
35+
var hasCompleted: Bool { get }
36+
var cachedResults: RetrieveResults? { get }
37+
}
3538

3639
class InAppProductQueryRequest: NSObject, InAppProductRequest, SKProductsRequestDelegate {
3740

3841
private let callback: InAppProductRequestCallback
3942
private let request: SKProductsRequest
4043

44+
private(set) var cachedResults: RetrieveResults?
45+
46+
var hasCompleted: Bool { cachedResults != nil }
47+
4148
deinit {
4249
request.delegate = nil
4350
}
@@ -52,6 +59,7 @@ class InAppProductQueryRequest: NSObject, InAppProductRequest, SKProductsRequest
5259
func start() {
5360
request.start()
5461
}
62+
5563
func cancel() {
5664
request.cancel()
5765
}
@@ -61,8 +69,12 @@ class InAppProductQueryRequest: NSObject, InAppProductRequest, SKProductsRequest
6169

6270
let retrievedProducts = Set<SKProduct>(response.products)
6371
let invalidProductIDs = Set<String>(response.invalidProductIdentifiers)
64-
performCallback(RetrieveResults(retrievedProducts: retrievedProducts,
65-
invalidProductIDs: invalidProductIDs, error: nil))
72+
let results = RetrieveResults(
73+
retrievedProducts: retrievedProducts,
74+
invalidProductIDs: invalidProductIDs, error: nil
75+
)
76+
self.cachedResults = results
77+
performCallback(results)
6678
}
6779

6880
func requestDidFinish(_ request: SKRequest) {

Sources/SwiftyStoreKit/OS.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public struct SKError: Error {
4646
self._nsError = _nsError
4747
}
4848

49-
var code: Code {
49+
public var code: Code {
5050
return Code(rawValue: _nsError.code) ?? .unknown
5151
}
5252

Sources/SwiftyStoreKit/PaymentQueueController.swift

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ extension SKPaymentTransactionState: CustomDebugStringConvertible {
8888
}
8989
}
9090

91+
struct EntitlementRevocation {
92+
let callback: ([String]) -> Void
93+
94+
init(callback: @escaping ([String]) -> Void) {
95+
self.callback = callback
96+
}
97+
}
98+
9199
class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
92100

93101
private let paymentsController: PaymentsController
@@ -97,7 +105,9 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
97105
private let completeTransactionsController: CompleteTransactionsController
98106

99107
unowned let paymentQueue: PaymentQueue
100-
108+
109+
private var entitlementRevocation: EntitlementRevocation?
110+
101111
deinit {
102112
paymentQueue.remove(self)
103113
}
@@ -145,6 +155,15 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
145155
paymentsController.append(payment)
146156
}
147157

158+
func onEntitlementRevocation(_ revocation: EntitlementRevocation) {
159+
guard entitlementRevocation == nil else {
160+
print("SwiftyStoreKit.onEntitlementRevocation() should only be called once when the app launches. Ignoring this call")
161+
return
162+
}
163+
164+
self.entitlementRevocation = revocation
165+
}
166+
148167
func restorePurchases(_ restorePurchases: RestorePurchases) {
149168
assertCompleteTransactionsWasCalled()
150169

@@ -206,7 +225,7 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
206225
* Failed transactions only ever belong to queued payment requests.
207226
* restoreCompletedTransactionsFailedWithError is always called when a restore purchases request fails.
208227
* paymentQueueRestoreCompletedTransactionsFinished is always called following 0 or more update transactions when a restore purchases request succeeds.
209-
* A complete transactions handler is require to catch any transactions that are updated when the app is not running.
228+
* A complete transactions handler is required to catch any transactions that are updated when the app is not running.
210229
* Registering a complete transactions handler when the app launches ensures that any pending transactions can be cleared.
211230
* If a complete transactions handler is missing, pending transactions can be mis-attributed to any new incoming payments or restore purchases.
212231
*
@@ -233,6 +252,11 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
233252
}
234253
}
235254

255+
func paymentQueue(_ queue: SKPaymentQueue, didRevokeEntitlementsForProductIdentifiers productIdentifiers: [String]) {
256+
257+
self.entitlementRevocation?.callback(productIdentifiers)
258+
}
259+
236260
func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) {
237261

238262
}

Sources/SwiftyStoreKit/ProductsInfoController.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,21 @@ class ProductsInfoController: NSObject {
6969
}
7070
inflightRequests[productIds] = InAppProductQuery(request: request, completionHandlers: [completion])
7171
request.start()
72+
7273
return request
74+
7375
} else {
76+
7477
inflightRequests[productIds]!.completionHandlers.append(completion)
78+
79+
let query = inflightRequests[productIds]!
80+
81+
if query.request.hasCompleted {
82+
query.completionHandlers.forEach {
83+
$0(query.request.cachedResults!)
84+
}
85+
}
86+
7587
return inflightRequests[productIds]!.request
7688
}
7789
}

Sources/SwiftyStoreKit/SKProductDiscount+LocalizedPrice.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,3 @@ public extension SKProductDiscount {
6060
}
6161

6262
}
63-

Sources/SwiftyStoreKit/SwiftyStoreKit+Types.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ public enum VerifySubscriptionResult {
175175
case notPurchased
176176
}
177177

178-
public enum SubscriptionType {
178+
public enum SubscriptionType: Hashable {
179179
case autoRenewable
180180
case nonRenewing(validDuration: TimeInterval)
181181
}

Sources/SwiftyStoreKit/SwiftyStoreKit.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ public class SwiftyStoreKit {
8484

8585
paymentQueueController.completeTransactions(CompleteTransactions(atomically: atomically, callback: completion))
8686
}
87+
88+
fileprivate func onEntitlementRevocation(completion: @escaping ([String]) -> Void) {
89+
90+
paymentQueueController.onEntitlementRevocation(EntitlementRevocation(callback: completion))
91+
}
8792

8893
fileprivate func finishTransaction(_ transaction: PaymentTransaction) {
8994

@@ -187,6 +192,14 @@ extension SwiftyStoreKit {
187192

188193
sharedInstance.completeTransactions(atomically: atomically, completion: completion)
189194
}
195+
196+
/// Entitlement revocation notification
197+
/// - Parameter completion: handler for result (list of product identifiers revoked)
198+
@available(iOS 14, tvOS 14, OSX 11, watchOS 7, macCatalyst 14, *)
199+
public class func onEntitlementRevocation(completion: @escaping ([String]) -> Void) {
200+
201+
sharedInstance.onEntitlementRevocation(completion: completion)
202+
}
190203

191204
/// Finish a transaction
192205
///

0 commit comments

Comments
 (0)