Skip to content

Commit

Permalink
StoreKit 1: disabled finishTransactions log on observer mode (#3314)
Browse files Browse the repository at this point in the history
  • Loading branch information
NachoSoto authored Oct 20, 2023
1 parent c3629d6 commit a9ae7bd
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 12 deletions.
23 changes: 16 additions & 7 deletions Sources/Logging/Strings/PurchaseStrings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ enum PurchaseStrings {
case paymentqueue_removed_transaction(SKPaymentTransactionObserver,
SKPaymentTransaction)
case paymentqueue_removed_transaction_no_callbacks_found(SKPaymentTransactionObserver,
SKPaymentTransaction)
SKPaymentTransaction,
observerMode: Bool)
case paymentqueue_updated_transaction(SKPaymentTransactionObserver,
SKPaymentTransaction)
case presenting_code_redemption_sheet
Expand Down Expand Up @@ -163,12 +164,20 @@ extension PurchaseStrings: LogMessage {
.compactMap { $0 }
.joined(separator: " ")

case let .paymentqueue_removed_transaction_no_callbacks_found(observer, transaction):
return "\(observer.debugName) removedTransaction for \(transaction.payment.productIdentifier) " +
"but no callbacks to notify.\n" +
"If the purchase completion block is not being invoked after this, it likely means that some other code " +
"outside of the RevenueCat SDK is calling `SKPaymentQueue.finishTransaction`, which is interfering with " +
"RevenueCat purchasing state handling."
case let .paymentqueue_removed_transaction_no_callbacks_found(observer, transaction, observerMode):
// Transactions finished with observer mode won't have a callback because they're being finished
// by the developer and not our SDK.
let shouldIncludeCompletionBlockMessage = !observerMode

let prefix = "\(observer.debugName) removedTransaction for \(transaction.payment.productIdentifier) " +
"but no callbacks to notify."
let completionBlockMessage = "If the purchase completion block is not being invoked after this, " +
"it likely means that some other code outside of the RevenueCat SDK is calling " +
"`SKPaymentQueue.finishTransaction`, which is interfering with RevenueCat purchasing state handling."

return shouldIncludeCompletionBlockMessage
? prefix + "\n" + completionBlockMessage
: prefix

case let .paymentqueue_updated_transaction(observer, transaction):
return "\(observer.debugName) updatedTransaction: \(transaction.payment.productIdentifier) " +
Expand Down
6 changes: 5 additions & 1 deletion Sources/Purchasing/Purchases/Purchases.swift
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,11 @@ public typealias StartPurchaseBlock = (@escaping PurchaseCompletedBlock) -> Void

let paymentQueueWrapper: EitherPaymentQueueWrapper = systemInfo.storeKit2Setting.shouldOnlyUseStoreKit2
? .right(.init())
: .left(.init(operationDispatcher: operationDispatcher, sandboxEnvironmentDetector: systemInfo))
: .left(.init(
operationDispatcher: operationDispatcher,
observerMode: observerMode,
sandboxEnvironmentDetector: systemInfo
))

let offeringsFactory = OfferingsFactory()
let receiptParser = PurchasesReceiptParser.default
Expand Down
10 changes: 8 additions & 2 deletions Sources/Purchasing/StoreKit1/StoreKit1Wrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,16 @@ class StoreKit1Wrapper: NSObject {

private let paymentQueue: SKPaymentQueue
private let operationDispatcher: OperationDispatcher
private let observerMode: Bool
private let sandboxEnvironmentDetector: SandboxEnvironmentDetector

init(paymentQueue: SKPaymentQueue = .default(),
operationDispatcher: OperationDispatcher = .default,
observerMode: Bool,
sandboxEnvironmentDetector: SandboxEnvironmentDetector = BundleSandboxEnvironmentDetector.default) {
self.paymentQueue = paymentQueue
self.operationDispatcher = operationDispatcher
self.observerMode = observerMode
self.sandboxEnvironmentDetector = sandboxEnvironmentDetector

super.init()
Expand Down Expand Up @@ -211,8 +214,11 @@ extension StoreKit1Wrapper: SKPaymentTransactionObserver {
!callbacks.isEmpty {
callbacks.forEach { $0() }
} else {
Logger.debug(Strings.purchase.paymentqueue_removed_transaction_no_callbacks_found(self,
transaction))
Logger.debug(Strings.purchase.paymentqueue_removed_transaction_no_callbacks_found(
self,
transaction,
observerMode: self.observerMode
))
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Tests/StoreKitUnitTests/PurchasesOrchestratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class PurchasesOrchestratorTests: StoreKitConfigTestCase {
}

fileprivate func setUpStoreKit1Wrapper() {
self.storeKit1Wrapper = MockStoreKit1Wrapper()
self.storeKit1Wrapper = MockStoreKit1Wrapper(observerMode: self.systemInfo.observerMode)
self.storeKit1Wrapper.mockAddPaymentTransactionState = .purchased
self.storeKit1Wrapper.mockCallUpdatedTransactionInstantly = true

Expand Down
4 changes: 4 additions & 0 deletions Tests/UnitTests/Mocks/MockStoreKit1Wrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
import StoreKit

class MockStoreKit1Wrapper: StoreKit1Wrapper {
init(observerMode: Bool = false) {
super.init(observerMode: observerMode)
}

var payment: SKPayment?
var addPaymentCallCount = 0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ class BasePurchasesTests: TestCase {
// this level it should be moved to `StoreKitUnitTests`, which runs serially.
Purchases.logLevel = .verbose

self.storeKit1Wrapper = MockStoreKit1Wrapper()
self.notificationCenter = MockNotificationCenter()
self.purchasesDelegate = MockPurchasesDelegate()

Expand All @@ -41,6 +40,7 @@ class BasePurchasesTests: TestCase {
self.systemInfo = MockSystemInfo(finishTransactions: true,
storeKit2Setting: self.storeKit2Setting,
clock: self.clock)
self.storeKit1Wrapper = MockStoreKit1Wrapper(observerMode: self.systemInfo.observerMode)
self.deviceCache = MockDeviceCache(sandboxEnvironmentDetector: self.systemInfo,
userDefaults: self.userDefaults)
self.paywallCache = .init()
Expand Down Expand Up @@ -228,6 +228,7 @@ class BasePurchasesTests: TestCase {
finishTransactions: false,
storeKit2Setting: self.storeKit2Setting,
clock: self.clock)
self.storeKit1Wrapper = MockStoreKit1Wrapper(observerMode: true)
self.initializePurchasesInstance(appUserId: nil)
}

Expand Down
1 change: 1 addition & 0 deletions Tests/UnitTests/Purchasing/StoreKit1WrapperTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class StoreKit1WrapperTests: TestCase, StoreKit1WrapperDelegate {

self.wrapper = StoreKit1Wrapper(paymentQueue: self.paymentQueue,
operationDispatcher: self.operationDispatcher,
observerMode: false,
sandboxEnvironmentDetector: self.sandboxEnvironmentDetector)
self.wrapper.delegate = self
}
Expand Down

0 comments on commit a9ae7bd

Please sign in to comment.