From 19ab18e0e8ebcef7f6cdfb1b12e7ac6619e1f7cc Mon Sep 17 00:00:00 2001 From: Artem Date: Sun, 24 Mar 2024 14:55:00 +0100 Subject: [PATCH] Fix to ensure restoreTransactions completion callback is called #150 Inside RMStore, when the paymentQueue:updatedTransactions is called after a restore, a pendingRestoredTransactions counter was incremented/decremented as transactions were processed. However, in our case updateTransactions callback was called twice, so 2x the amount of transactions were added to the pendingRestoredTransactions counter. The problem was the counter was incremented twice but only decremented once for each transaction. WHen the code reached notifyRestoreTransactionFinishedIfApplicableAfterTransaction, the counter was checked but was not equal to zero, so the callback wasn't called, even though all the transactions were processed. The fix was to use a MutableSet to store transaction identifiers that were pending restore, which prevents duplicate transactions to be handled. The callback is now always called after transactions are restored. --- RMStore/RMStore.m | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/RMStore/RMStore.m b/RMStore/RMStore.m index 93dbd89a..01388b12 100755 --- a/RMStore/RMStore.m +++ b/RMStore/RMStore.m @@ -138,7 +138,7 @@ @implementation RMStore { NSMutableArray *_storedStorePayments; - NSInteger _pendingRestoredTransactionsCount; + NSMutableSet *_pendingRestoredTransactionIds; BOOL _restoredCompletedTransactionsFinished; SKReceiptRefreshRequest *_refreshReceiptRequest; @@ -158,6 +158,7 @@ - (instancetype) init _productsRequestDelegates = [NSMutableSet set]; _restoredTransactions = [NSMutableArray array]; _storedStorePayments = [NSMutableArray array]; + _pendingRestoredTransactionIds = [NSMutableSet set]; [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; } return self; @@ -265,7 +266,7 @@ - (void)restoreTransactionsOnSuccess:(void (^)(NSArray *transactions))successBlo failure:(void (^)(NSError *error))failureBlock { _restoredCompletedTransactionsFinished = NO; - _pendingRestoredTransactionsCount = 0; + [_pendingRestoredTransactionIds removeAllObjects]; _restoredTransactions = [NSMutableArray array]; _restoreTransactionsSuccessBlock = successBlock; _restoreTransactionsFailureBlock = failureBlock; @@ -278,7 +279,7 @@ - (void)restoreTransactionsOfUser:(NSString*)userIdentifier { NSAssert([[SKPaymentQueue defaultQueue] respondsToSelector:@selector(restoreCompletedTransactionsWithApplicationUsername:)], @"restoreCompletedTransactionsWithApplicationUsername: not supported in this iOS version. Use restoreTransactionsOnSuccess:failure: instead."); _restoredCompletedTransactionsFinished = NO; - _pendingRestoredTransactionsCount = 0; + [_pendingRestoredTransactionIds removeAllObjects]; _restoreTransactionsSuccessBlock = successBlock; _restoreTransactionsFailureBlock = failureBlock; [[SKPaymentQueue defaultQueue] restoreCompletedTransactionsWithApplicationUsername:userIdentifier]; @@ -593,9 +594,13 @@ - (void)didFailTransaction:(SKPaymentTransaction *)transaction queue:(SKPaymentQ - (void)didRestoreTransaction:(SKPaymentTransaction *)transaction queue:(SKPaymentQueue*)queue { - RMStoreLog(@"transaction restored with product %@", transaction.originalTransaction.payment.productIdentifier); + NSString *productIdentifier = transaction.originalTransaction.payment.productIdentifier; + RMStoreLog(@"transaction restored with product %@", productIdentifier); - _pendingRestoredTransactionsCount++; + if (productIdentifier) + { + [_pendingRestoredTransactionIds addObject:productIdentifier]; + } if (self.receiptVerifier != nil) { [self.receiptVerifier verifyTransaction:transaction success:^{ @@ -695,9 +700,14 @@ - (void)notifyRestoreTransactionFinishedIfApplicableAfterTransaction:(SKPaymentT if (transaction != nil) { [_restoredTransactions addObject:transaction]; - _pendingRestoredTransactionsCount--; + + NSString *productIdentifier = transaction.payment.productIdentifier; + if (productIdentifier) + { + [_pendingRestoredTransactionIds removeObject:productIdentifier]; + } } - if (_restoredCompletedTransactionsFinished && _pendingRestoredTransactionsCount == 0) + if (_restoredCompletedTransactionsFinished && _pendingRestoredTransactionIds.count == 0) { // Wait until all restored transations have been verified NSArray *restoredTransactions = [_restoredTransactions copy]; if (_restoreTransactionsSuccessBlock != nil)