Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[in_app_purchase] Fix the bug that prevent restored subscription transactions from being completed #2872

Merged
merged 9 commits into from
Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
4 changes: 4 additions & 0 deletions packages/in_app_purchase/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.3.4+4

* iOS: Fix the bug that prevent restored subscription transactions from being completed

## 0.3.4+3

* Fixed typo 'manuelly' for 'manually'.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ typedef void (^UpdatedDownloads)(NSArray<SKDownload *> *downloads);
@interface FIAPaymentQueueHandler : NSObject <SKPaymentTransactionObserver>

// Unfinished transactions.
@property(nonatomic, readonly) NSDictionary<NSString *, SKPaymentTransaction *> *transactions;
@property(nonatomic, readonly)
NSDictionary<NSString *, NSMutableArray<SKPaymentTransaction *> *> *transactions;

- (instancetype)initWithQueue:(nonnull SKPaymentQueue *)queue
transactionsUpdated:(nullable TransactionsUpdated)transactionsUpdated
Expand Down
28 changes: 24 additions & 4 deletions packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ @interface FIAPaymentQueueHandler ()
@property(nullable, copy, nonatomic) UpdatedDownloads updatedDownloads;

@property(strong, nonatomic)
NSMutableDictionary<NSString *, SKPaymentTransaction *> *transactionsSetter;
NSMutableDictionary<NSString *, NSMutableArray<SKPaymentTransaction *> *> *transactionsSetter;

@end

Expand Down Expand Up @@ -81,7 +81,13 @@ - (void)paymentQueue:(SKPaymentQueue *)queue
// will become impossible for clients to finish deferred transactions when needed.
// 2. Using product identifiers can help prevent clients from purchasing the same
// subscription more than once by accident.
self.transactionsSetter[transaction.payment.productIdentifier] = transaction;
NSMutableArray *transactionArray =
[self.transactionsSetter objectForKey:transaction.payment.productIdentifier];
if (transactionArray == nil) {
transactionArray = [NSMutableArray array];
}
[transactionArray addObject:transaction];
self.transactionsSetter[transaction.payment.productIdentifier] = transactionArray;
}
}
// notify dart through callbacks.
Expand All @@ -92,7 +98,21 @@ - (void)paymentQueue:(SKPaymentQueue *)queue
- (void)paymentQueue:(SKPaymentQueue *)queue
removedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
[self.transactionsSetter removeObjectForKey:transaction.payment.productIdentifier];
NSString *productId = transaction.payment.productIdentifier;

if ([self.transactionsSetter objectForKey:productId] == nil) {
continue;
}

NSPredicate *predicate = [NSPredicate
predicateWithFormat:@"transactionIdentifier == %@", transaction.transactionIdentifier];
NSArray<SKPaymentTransaction *> *filteredTransactions =
[self.transactionsSetter[productId] filteredArrayUsingPredicate:predicate];
[self.transactionsSetter[productId] removeObjectsInArray:filteredTransactions];

if (!self.transactionsSetter[productId] || !self.transactionsSetter[productId].count) {
[self.transactionsSetter removeObjectForKey:productId];
}
}
self.transactionsRemoved(transactions);
}
Expand Down Expand Up @@ -128,7 +148,7 @@ - (BOOL)paymentQueue:(SKPaymentQueue *)queue

#pragma mark - getter

- (NSDictionary<NSString *, SKPaymentTransaction *> *)transactions {
- (NSDictionary<NSString *, NSMutableArray<SKPaymentTransaction *> *> *)transactions {
return [self.transactionsSetter copy];
}

Expand Down
11 changes: 6 additions & 5 deletions packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m
Original file line number Diff line number Diff line change
Expand Up @@ -204,24 +204,25 @@ - (void)finishTransaction:(FlutterMethodCall *)call result:(FlutterResult)result
return;
}
NSString *identifier = call.arguments;
SKPaymentTransaction *transaction =
[self.paymentQueueHandler.transactions objectForKey:identifier];
if (!transaction) {
NSMutableArray *transactions = [self.paymentQueueHandler.transactions objectForKey:identifier];
if (!transactions) {
result([FlutterError
errorWithCode:@"storekit_platform_invalid_transaction"
message:[NSString
stringWithFormat:@"The transaction with transactionIdentifer:%@ does not "
@"exist. Note that if the transactionState is "
@"purchasing, the transactionIdentifier will be "
@"nil(null).",
transaction.transactionIdentifier]
identifier]
details:call.arguments]);
return;
}
@try {
for (SKPaymentTransaction *transaction in transactions) {
[self.paymentQueueHandler finishTransaction:transaction];
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it ok to abort the loop if an exception is thrown or should you move try/catch inside the loop.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way for the user to know which transactions are failed when finishing?

// finish transaction will throw exception if the transaction type is purchasing. Notify dart
// about this exception.
[self.paymentQueueHandler finishTransaction:transaction];
} @catch (NSException *e) {
result([FlutterError errorWithCode:@"storekit_finish_transaction_exception"
message:e.name
Expand Down
2 changes: 1 addition & 1 deletion packages/in_app_purchase/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: in_app_purchase
description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play.
homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase
version: 0.3.4+3
version: 0.3.4+4

dependencies:
async: ^2.0.8
Expand Down