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

Commit ba09b7f

Browse files
authored
[in_app_purchase] Fix the bug that prevent restored subscription transactions from being completed (#2872)
* Fix the bug that prevent restored subscription transactions from being completed * Update changelog * increased version * fixed removing transactions from transactionsSetter * Fixed CHANGELOGS conflicts * transactionsSetter code formating updates * fixed formating
1 parent d6fdbbd commit ba09b7f

File tree

5 files changed

+37
-11
lines changed

5 files changed

+37
-11
lines changed

packages/in_app_purchase/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.3.4+6
2+
3+
* iOS: Fix the bug that prevent restored subscription transactions from being completed
4+
15
## 0.3.4+5
26

37
* Added necessary README docs for getting started with Android.

packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ typedef void (^UpdatedDownloads)(NSArray<SKDownload *> *downloads);
1919
@interface FIAPaymentQueueHandler : NSObject <SKPaymentTransactionObserver>
2020

2121
// Unfinished transactions.
22-
@property(nonatomic, readonly) NSDictionary<NSString *, SKPaymentTransaction *> *transactions;
22+
@property(nonatomic, readonly)
23+
NSDictionary<NSString *, NSMutableArray<SKPaymentTransaction *> *> *transactions;
2324

2425
- (instancetype)initWithQueue:(nonnull SKPaymentQueue *)queue
2526
transactionsUpdated:(nullable TransactionsUpdated)transactionsUpdated

packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ @interface FIAPaymentQueueHandler ()
1616
@property(nullable, copy, nonatomic) UpdatedDownloads updatedDownloads;
1717

1818
@property(strong, nonatomic)
19-
NSMutableDictionary<NSString *, SKPaymentTransaction *> *transactionsSetter;
19+
NSMutableDictionary<NSString *, NSMutableArray<SKPaymentTransaction *> *> *transactionsSetter;
2020

2121
@end
2222

@@ -81,7 +81,13 @@ - (void)paymentQueue:(SKPaymentQueue *)queue
8181
// will become impossible for clients to finish deferred transactions when needed.
8282
// 2. Using product identifiers can help prevent clients from purchasing the same
8383
// subscription more than once by accident.
84-
self.transactionsSetter[transaction.payment.productIdentifier] = transaction;
84+
NSMutableArray *transactionArray =
85+
[self.transactionsSetter objectForKey:transaction.payment.productIdentifier];
86+
if (transactionArray == nil) {
87+
transactionArray = [NSMutableArray array];
88+
}
89+
[transactionArray addObject:transaction];
90+
self.transactionsSetter[transaction.payment.productIdentifier] = transactionArray;
8591
}
8692
}
8793
// notify dart through callbacks.
@@ -92,7 +98,21 @@ - (void)paymentQueue:(SKPaymentQueue *)queue
9298
- (void)paymentQueue:(SKPaymentQueue *)queue
9399
removedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
94100
for (SKPaymentTransaction *transaction in transactions) {
95-
[self.transactionsSetter removeObjectForKey:transaction.payment.productIdentifier];
101+
NSString *productId = transaction.payment.productIdentifier;
102+
103+
if ([self.transactionsSetter objectForKey:productId] == nil) {
104+
continue;
105+
}
106+
107+
NSPredicate *predicate = [NSPredicate
108+
predicateWithFormat:@"transactionIdentifier == %@", transaction.transactionIdentifier];
109+
NSArray<SKPaymentTransaction *> *filteredTransactions =
110+
[self.transactionsSetter[productId] filteredArrayUsingPredicate:predicate];
111+
[self.transactionsSetter[productId] removeObjectsInArray:filteredTransactions];
112+
113+
if (!self.transactionsSetter[productId] || !self.transactionsSetter[productId].count) {
114+
[self.transactionsSetter removeObjectForKey:productId];
115+
}
96116
}
97117
self.transactionsRemoved(transactions);
98118
}
@@ -128,7 +148,7 @@ - (BOOL)paymentQueue:(SKPaymentQueue *)queue
128148

129149
#pragma mark - getter
130150

131-
- (NSDictionary<NSString *, SKPaymentTransaction *> *)transactions {
151+
- (NSDictionary<NSString *, NSMutableArray<SKPaymentTransaction *> *> *)transactions {
132152
return [self.transactionsSetter copy];
133153
}
134154

packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,24 +204,25 @@ - (void)finishTransaction:(FlutterMethodCall *)call result:(FlutterResult)result
204204
return;
205205
}
206206
NSString *identifier = call.arguments;
207-
SKPaymentTransaction *transaction =
208-
[self.paymentQueueHandler.transactions objectForKey:identifier];
209-
if (!transaction) {
207+
NSMutableArray *transactions = [self.paymentQueueHandler.transactions objectForKey:identifier];
208+
if (!transactions) {
210209
result([FlutterError
211210
errorWithCode:@"storekit_platform_invalid_transaction"
212211
message:[NSString
213212
stringWithFormat:@"The transaction with transactionIdentifer:%@ does not "
214213
@"exist. Note that if the transactionState is "
215214
@"purchasing, the transactionIdentifier will be "
216215
@"nil(null).",
217-
transaction.transactionIdentifier]
216+
identifier]
218217
details:call.arguments]);
219218
return;
220219
}
221220
@try {
221+
for (SKPaymentTransaction *transaction in transactions) {
222+
[self.paymentQueueHandler finishTransaction:transaction];
223+
}
222224
// finish transaction will throw exception if the transaction type is purchasing. Notify dart
223225
// about this exception.
224-
[self.paymentQueueHandler finishTransaction:transaction];
225226
} @catch (NSException *e) {
226227
result([FlutterError errorWithCode:@"storekit_finish_transaction_exception"
227228
message:e.name

packages/in_app_purchase/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: in_app_purchase
22
description: A Flutter plugin for in-app purchases. Exposes APIs for making in-app purchases through the App Store and Google Play.
33
homepage: https://github.com/flutter/plugins/tree/master/packages/in_app_purchase
4-
version: 0.3.4+5
4+
version: 0.3.4+6
55

66
dependencies:
77
async: ^2.0.8

0 commit comments

Comments
 (0)