Skip to content

Commit

Permalink
Fix certain completion blocks not being dispatched on the main thread (
Browse files Browse the repository at this point in the history
…#4058)

Some completion blocks were not being dispatched to the main thread.
These include:

- Checking intro trial eligibility in SK1 and SK2
- Promo offer eligibility in SK1 and SK2
- Syncing/restoring purchases in SK2 when there are no transactions and
there is a cached customer info

### Checklist
- [ ] If applicable, unit tests
- [ ] If applicable, create follow-up issues for `purchases-android` and
hybrids

### Motivation
<!-- Why is this change required? What problem does it solve? -->
<!-- Please link to issues following this format: Resolves #999999 -->

### Description
<!-- Describe your changes in detail -->
<!-- Please describe in detail how you tested your changes -->
  • Loading branch information
MarkVillacampa authored and nyeu committed Oct 1, 2024
1 parent 53e4d2c commit aae5c74
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 11 deletions.
20 changes: 15 additions & 5 deletions Sources/Purchasing/Purchases/PurchasesOrchestrator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,16 @@ final class PurchasesOrchestrator {
product: StoreProductType,
completion: @escaping @Sendable (Result<PromotionalOffer, PurchasesError>) -> Void) {
guard let discountIdentifier = productDiscount.offerIdentifier else {
completion(.failure(ErrorUtils.productDiscountMissingIdentifierError()))
self.operationDispatcher.dispatchOnMainActor {
completion(.failure(ErrorUtils.productDiscountMissingIdentifierError()))
}
return
}

guard let subscriptionGroupIdentifier = product.subscriptionGroupIdentifier else {
completion(.failure(ErrorUtils.productDiscountMissingSubscriptionGroupIdentifierError()))
self.operationDispatcher.dispatchOnMainActor {
completion(.failure(ErrorUtils.productDiscountMissingSubscriptionGroupIdentifierError()))
}
return
}

Expand All @@ -284,14 +288,18 @@ final class PurchasesOrchestrator {
discountIdentifier: discountIdentifier,
product: product,
subscriptionGroupIdentifier: subscriptionGroupIdentifier) { result in
completion(result)
self.operationDispatcher.dispatchOnMainActor {
completion(result)
}
}
} else {
self.sk1PromotionalOffer(forProductDiscount: productDiscount,
discountIdentifier: discountIdentifier,
product: product,
subscriptionGroupIdentifier: subscriptionGroupIdentifier) { result in
completion(result)
self.operationDispatcher.dispatchOnMainActor {
completion(result)
}
}

}
Expand Down Expand Up @@ -1125,7 +1133,9 @@ private extension PurchasesOrchestrator {
if let cachedCustomerInfo,
cachedCustomerInfo.originalPurchaseDate != nil,
cachedCustomerInfo.originalApplicationVersion != nil {
completion?(.success(cachedCustomerInfo))
self.operationDispatcher.dispatchOnMainActor {
completion?(.success(cachedCustomerInfo))
}
return
}

Expand Down
31 changes: 25 additions & 6 deletions Sources/Purchasing/TrialOrIntroPriceEligibilityChecker.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,18 @@ class TrialOrIntroPriceEligibilityChecker: TrialOrIntroPriceEligibilityCheckerTy
return
}

// Extracting and wrapping the completion block from the async call
// to avoid having to mark ReceiveIntroEligibilityBlock as @Sendable
// up to the public API thus making a breaking change.
let completionBlock: ReceiveIntroEligibilityBlock = { result in
self.operationDispatcher.dispatchOnMainActor {
completion(result)
}
}

if #available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *),
self.systemInfo.storeKitVersion.isStoreKit2EnabledAndAvailable {
Async.call(with: completion) {
Async.call(with: completionBlock) {
do {
return try await self.sk2CheckEligibility(productIdentifiers)
} catch {
Expand All @@ -74,7 +83,11 @@ class TrialOrIntroPriceEligibilityChecker: TrialOrIntroPriceEligibilityCheckerTy
}
}
} else {
self.sk1CheckEligibility(productIdentifiers, completion: completion)
self.sk1CheckEligibility(productIdentifiers) { result in
self.operationDispatcher.dispatchOnMainActor {
completion(result)
}
}
}
}

Expand All @@ -85,12 +98,18 @@ class TrialOrIntroPriceEligibilityChecker: TrialOrIntroPriceEligibilityCheckerTy
self.receiptFetcher.receiptData(refreshPolicy: .never) { data, _ in
if let data = data {
self.sk1CheckEligibility(with: data,
productIdentifiers: productIdentifiers,
completion: completion)
productIdentifiers: productIdentifiers) { eligibility in
self.operationDispatcher.dispatchOnMainActor {
completion(eligibility)
}
}
} else {
self.getIntroEligibility(with: data ?? Data(),
productIdentifiers: productIdentifiers,
completion: completion)
productIdentifiers: productIdentifiers) { eligibility in
self.operationDispatcher.dispatchOnMainActor {
completion(eligibility)
}
}
}
}
}
Expand Down

0 comments on commit aae5c74

Please sign in to comment.