Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some Bug Fixes & Improvements #610

Merged
merged 29 commits into from
Jan 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
34ef0d4
feat: add failing test for ProductInfoController.inflightRequest - crash
Sep 30, 2019
511f4b1
fix: reduce the amount of products
Sep 30, 2019
947382f
docs: add comments to the test
Sep 30, 2019
76e83e0
fix: make the test works properly, calling the fireCallbakcs method.
Sep 30, 2019
72f88b0
fix: implement OS agnostic locking.
Sep 30, 2019
d3ed588
fix: lock the retrieveProductsInfo so that it’s thread safe.
Sep 30, 2019
23f0f2d
docs: add changelog
Sep 30, 2019
f5d9858
fix: remove api available only on macos and only from version 10
Sep 30, 2019
b8ee2d3
fix: reduce the wait time to fire the callbacks
Sep 30, 2019
6aca8f0
make watchos SKError.code public so that it's accessible outside of t…
motocodeltd Jul 20, 2020
38d34da
Make `SubscriptionType` Hashable.
Jul 22, 2020
6004597
add support for ios14 entitlement revocation
motocodeltd Aug 15, 2020
3e7d70d
add entitlement revocation only once
motocodeltd Aug 15, 2020
f0a4198
add entitlement revocation only once
motocodeltd Aug 15, 2020
ee7b4e4
Merge pull request #563 from motocodeltd/make_watchos_code_public
Sam-Spencer Aug 15, 2020
f067745
Merge pull request #565 from Pimine/master
Sam-Spencer Aug 15, 2020
daddd07
Merge pull request #572 from motocodeltd/add_support_for_entitlement_…
Sam-Spencer Aug 15, 2020
40cca01
Integrating PR #495
Sam-Spencer Aug 15, 2020
f6d7745
Fix typo in code comment
revolter Sep 9, 2020
f6588ae
Merge pull request #575 from revolter/patch-1
Sam-Spencer Sep 9, 2020
dd0e6f2
Added Botcher to apps using SwiftStoreKit
martino-dot Sep 20, 2020
02163c3
Update Package.swift
Sam-Spencer Sep 21, 2020
24a58ab
Call completion closure on completed request
muukii Sep 28, 2020
b2c030b
Adds Hashr to showcase apps
d-rr Oct 21, 2020
849212d
Merge pull request #591 from d-rr/patch-2
Sam-Spencer Jan 4, 2021
1368f0d
Merge branch 'develop' into develop
Sam-Spencer Jan 4, 2021
312ae6e
Merge pull request #582 from martino-dot/develop
Sam-Spencer Jan 4, 2021
e9815a1
Merge pull request #584 from muukii/muukii/handle-completed-request
Sam-Spencer Jan 4, 2021
70761d2
Update ProductsInfoController.swift
Sam-Spencer Jan 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

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

* 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)

## [0.15.0](https://github.com/bizz84/SwiftyStoreKit/releases/tag/0.15.0) Update project to Swift 5, Xcode 10.2

* Update project to Swift 5 ([#457](https://github.com/bizz84/SwiftyStoreKit/pull/457)), related issue: [#456](https://github.com/bizz84/SwiftyStoreKit/issues/456)
Expand Down
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ let package = Package(
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "SwiftyStoreKit",
targets: ["SwiftyStoreKit"]),
targets: ["SwiftyStoreKit"])
],
dependencies: [
// Dependencies declare other packages that this package depends on.
Expand All @@ -22,6 +22,6 @@ let package = Package(
dependencies: []),
.testTarget(
name: "SwiftyStoreKitTests",
dependencies: ["SwiftyStoreKit"]),
dependencies: ["SwiftyStoreKit"])
]
)
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -798,6 +798,8 @@ It would be great to showcase apps using SwiftyStoreKit here. Pull requests welc
* [Talk Dim Sum](https://itunes.apple.com/us/app/talk-dim-sum/id953929066) - Your dim sum companion
* [Sluggard](https://itunes.apple.com/app/id1160131071) - Perform simple exercises to reduce the risks of sedentary lifestyle
* [Debts iOS](https://debts.ivanvorobei.by/ios) & [Debts macOS](https://debts.ivanvorobei.by/macos) - Track amounts owed
* [Botcher](https://itunes.apple.com/us/app/id1522337788) - Good for finding something to do
* [Hashr](https://apps.apple.com/app/id1166499829) - Generate unique password hashes based on website and master password

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

Expand Down
18 changes: 15 additions & 3 deletions Sources/SwiftyStoreKit/InAppProductQueryRequest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,20 @@ public protocol InAppRequest: class {
func cancel()
}

protocol InAppProductRequest: InAppRequest { }
protocol InAppProductRequest: InAppRequest {
var hasCompleted: Bool { get }
var cachedResults: RetrieveResults? { get }
}

class InAppProductQueryRequest: NSObject, InAppProductRequest, SKProductsRequestDelegate {

private let callback: InAppProductRequestCallback
private let request: SKProductsRequest

private(set) var cachedResults: RetrieveResults?

var hasCompleted: Bool { cachedResults != nil }

deinit {
request.delegate = nil
}
Expand All @@ -52,6 +59,7 @@ class InAppProductQueryRequest: NSObject, InAppProductRequest, SKProductsRequest
func start() {
request.start()
}

func cancel() {
request.cancel()
}
Expand All @@ -61,8 +69,12 @@ class InAppProductQueryRequest: NSObject, InAppProductRequest, SKProductsRequest

let retrievedProducts = Set<SKProduct>(response.products)
let invalidProductIDs = Set<String>(response.invalidProductIdentifiers)
performCallback(RetrieveResults(retrievedProducts: retrievedProducts,
invalidProductIDs: invalidProductIDs, error: nil))
let results = RetrieveResults(
retrievedProducts: retrievedProducts,
invalidProductIDs: invalidProductIDs, error: nil
)
self.cachedResults = results
performCallback(results)
}

func requestDidFinish(_ request: SKRequest) {
Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftyStoreKit/OS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public struct SKError: Error {
self._nsError = _nsError
}

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

Expand Down
28 changes: 26 additions & 2 deletions Sources/SwiftyStoreKit/PaymentQueueController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,14 @@ extension SKPaymentTransactionState: CustomDebugStringConvertible {
}
}

struct EntitlementRevocation {
let callback: ([String]) -> Void

init(callback: @escaping ([String]) -> Void) {
self.callback = callback
}
}

class PaymentQueueController: NSObject, SKPaymentTransactionObserver {

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

unowned let paymentQueue: PaymentQueue


private var entitlementRevocation: EntitlementRevocation?

deinit {
paymentQueue.remove(self)
}
Expand Down Expand Up @@ -145,6 +155,15 @@ class PaymentQueueController: NSObject, SKPaymentTransactionObserver {
paymentsController.append(payment)
}

func onEntitlementRevocation(_ revocation: EntitlementRevocation) {
guard entitlementRevocation == nil else {
print("SwiftyStoreKit.onEntitlementRevocation() should only be called once when the app launches. Ignoring this call")
return
}

self.entitlementRevocation = revocation
}

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

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

func paymentQueue(_ queue: SKPaymentQueue, didRevokeEntitlementsForProductIdentifiers productIdentifiers: [String]) {

self.entitlementRevocation?.callback(productIdentifiers)
}

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

}
Expand Down
12 changes: 12 additions & 0 deletions Sources/SwiftyStoreKit/ProductsInfoController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,21 @@ class ProductsInfoController: NSObject {
}
inflightRequests[productIds] = InAppProductQuery(request: request, completionHandlers: [completion])
request.start()

return request

} else {

inflightRequests[productIds]!.completionHandlers.append(completion)

let query = inflightRequests[productIds]!

if query.request.hasCompleted {
query.completionHandlers.forEach {
$0(query.request.cachedResults!)
}
}

return inflightRequests[productIds]!.request
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,3 @@ public extension SKProductDiscount {
}

}

2 changes: 1 addition & 1 deletion Sources/SwiftyStoreKit/SwiftyStoreKit+Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ public enum VerifySubscriptionResult {
case notPurchased
}

public enum SubscriptionType {
public enum SubscriptionType: Hashable {
case autoRenewable
case nonRenewing(validDuration: TimeInterval)
}
Expand Down
13 changes: 13 additions & 0 deletions Sources/SwiftyStoreKit/SwiftyStoreKit.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ public class SwiftyStoreKit {

paymentQueueController.completeTransactions(CompleteTransactions(atomically: atomically, callback: completion))
}

fileprivate func onEntitlementRevocation(completion: @escaping ([String]) -> Void) {

paymentQueueController.onEntitlementRevocation(EntitlementRevocation(callback: completion))
}

fileprivate func finishTransaction(_ transaction: PaymentTransaction) {

Expand Down Expand Up @@ -187,6 +192,14 @@ extension SwiftyStoreKit {

sharedInstance.completeTransactions(atomically: atomically, completion: completion)
}

/// Entitlement revocation notification
/// - Parameter completion: handler for result (list of product identifiers revoked)
@available(iOS 14, tvOS 14, OSX 11, watchOS 7, macCatalyst 14, *)
public class func onEntitlementRevocation(completion: @escaping ([String]) -> Void) {

sharedInstance.onEntitlementRevocation(completion: completion)
}

/// Finish a transaction
///
Expand Down
Loading