[in_app_purchase] Expose SKPaymentQueue.transactions to dart (#2510)
diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md
index b1b3f2a..647ff0b 100644
--- a/packages/in_app_purchase/CHANGELOG.md
+++ b/packages/in_app_purchase/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.3.3
+
+* Introduce `SKPaymentQueueWrapper.transactions`.
+
## 0.3.2+2
* Fix CocoaPods podspec lint warnings.
diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h
index 55b9ca9..ed17881 100644
--- a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h
+++ b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.h
@@ -32,6 +32,7 @@
// Can throw exceptions if the transaction type is purchasing, should always used in a @try block.
- (void)finishTransaction:(nonnull SKPaymentTransaction *)transaction;
- (void)restoreTransactions:(nullable NSString *)applicationName;
+- (NSArray<SKPaymentTransaction *> *)getUnfinishedTransactions;
// This method needs to be called before any other methods.
- (void)startObservingPaymentQueue;
diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m
index 8ca39dd..8bdb7f2 100644
--- a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m
+++ b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m
@@ -124,6 +124,10 @@
return (self.shouldAddStorePayment(payment, product));
}
+- (NSArray<SKPaymentTransaction *> *)getUnfinishedTransactions {
+ return self.queue.transactions;
+}
+
#pragma mark - getter
- (NSDictionary<NSString *, SKPaymentTransaction *> *)transactions {
diff --git a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m
index 4d2a55f..bfe29f9 100644
--- a/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m
+++ b/packages/in_app_purchase/ios/Classes/InAppPurchasePlugin.m
@@ -83,6 +83,8 @@
- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
if ([@"-[SKPaymentQueue canMakePayments:]" isEqualToString:call.method]) {
[self canMakePayments:result];
+ } else if ([@"-[SKPaymentQueue transactions]" isEqualToString:call.method]) {
+ [self getPendingTransactions:result];
} else if ([@"-[InAppPurchasePlugin startProductRequest:result:]" isEqualToString:call.method]) {
[self handleProductRequestMethodCall:call result:result];
} else if ([@"-[InAppPurchasePlugin addPayment:result:]" isEqualToString:call.method]) {
@@ -104,6 +106,16 @@
result([NSNumber numberWithBool:[SKPaymentQueue canMakePayments]]);
}
+- (void)getPendingTransactions:(FlutterResult)result {
+ NSArray<SKPaymentTransaction *> *transactions =
+ [self.paymentQueueHandler getUnfinishedTransactions];
+ NSMutableArray *transactionMaps = [[NSMutableArray alloc] init];
+ for (SKPaymentTransaction *transaction in transactions) {
+ [transactionMaps addObject:[FIAObjectTranslator getMapFromSKPaymentTransaction:transaction]];
+ }
+ result(transactionMaps);
+}
+
- (void)handleProductRequestMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
if (![call.arguments isKindOfClass:[NSArray class]]) {
result([FlutterError errorWithCode:@"storekit_invalid_argument"
diff --git a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m
index eeb76d2..e6a18e0 100644
--- a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m
+++ b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#import <OCMock/OCMock.h>
#import <XCTest/XCTest.h>
#import "FIAPaymentQueueHandler.h"
#import "Stubs.h"
@@ -248,4 +249,39 @@
XCTAssertTrue(result);
}
+- (void)testGetPendingTransactions {
+ XCTestExpectation* expectation = [self expectationWithDescription:@"expect success"];
+ FlutterMethodCall* call =
+ [FlutterMethodCall methodCallWithMethodName:@"-[SKPaymentQueue transactions]" arguments:nil];
+ SKPaymentQueue* mockQueue = OCMClassMock(SKPaymentQueue.class);
+ NSDictionary* transactionMap = @{
+ @"transactionIdentifier" : [NSNull null],
+ @"transactionState" : @(SKPaymentTransactionStatePurchasing),
+ @"payment" : [NSNull null],
+ @"error" : [FIAObjectTranslator getMapFromNSError:[NSError errorWithDomain:@"test_stub"
+ code:123
+ userInfo:@{}]],
+ @"transactionTimeStamp" : @([NSDate date].timeIntervalSince1970),
+ @"originalTransaction" : [NSNull null],
+ };
+ OCMStub(mockQueue.transactions).andReturn(@[ [[SKPaymentTransactionStub alloc]
+ initWithMap:transactionMap] ]);
+
+ __block NSArray* resultArray;
+ self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:mockQueue
+ transactionsUpdated:nil
+ transactionRemoved:nil
+ restoreTransactionFailed:nil
+ restoreCompletedTransactionsFinished:nil
+ shouldAddStorePayment:nil
+ updatedDownloads:nil];
+ [self.plugin handleMethodCall:call
+ result:^(id r) {
+ resultArray = r;
+ [expectation fulfill];
+ }];
+ [self waitForExpectations:@[ expectation ] timeout:5];
+ XCTAssertEqualObjects(resultArray, @[ transactionMap ]);
+}
+
@end
diff --git a/packages/in_app_purchase/ios/in_app_purchase.podspec b/packages/in_app_purchase/ios/in_app_purchase.podspec
index 60109eb..8da9d78 100644
--- a/packages/in_app_purchase/ios/in_app_purchase.podspec
+++ b/packages/in_app_purchase/ios/in_app_purchase.podspec
@@ -22,5 +22,6 @@
s.test_spec 'Tests' do |test_spec|
test_spec.source_files = 'Tests/**/*'
+ test_spec.dependency 'OCMock','3.5'
end
end
diff --git a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart
index 036c602..49c438e 100644
--- a/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart
+++ b/packages/in_app_purchase/lib/src/store_kit_wrappers/sk_payment_queue_wrapper.dart
@@ -41,6 +41,12 @@
callbackChannel.setMethodCallHandler(_handleObserverCallbacks);
}
+ /// Calls [`-[SKPaymentQueue transactions]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506026-transactions?language=objc)
+ Future<List<SKPaymentTransactionWrapper>> transactions() async {
+ return _getTransactionList(
+ await channel.invokeListMethod<Map>('-[SKPaymentQueue transactions]'));
+ }
+
/// Calls [`-[SKPaymentQueue canMakePayments:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506139-canmakepayments?language=objc).
static Future<bool> canMakePayments() async =>
await channel.invokeMethod<bool>('-[SKPaymentQueue canMakePayments:]');
diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml
index ee04f34..ac8971e 100644
--- a/packages/in_app_purchase/pubspec.yaml
+++ b/packages/in_app_purchase/pubspec.yaml
@@ -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.2+2
+version: 0.3.3
dependencies:
async: ^2.0.8
diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart
index 78c3c2e..c8da68a 100644
--- a/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart
+++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_methodchannel_apis_test.dart
@@ -83,6 +83,10 @@
expect(await SKPaymentQueueWrapper.canMakePayments(), true);
});
+ test('transactions should return a valid list of transactions', () async {
+ expect(await SKPaymentQueueWrapper().transactions(), isNotEmpty);
+ });
+
test(
'throws if observer is not set for payment queue before adding payment',
() async {
@@ -161,6 +165,8 @@
// payment queue
case '-[SKPaymentQueue canMakePayments:]':
return Future<bool>.value(true);
+ case '-[SKPaymentQueue transactions]':
+ return Future<List<Map>>.value([buildTransactionMap(dummyTransaction)]);
case '-[InAppPurchasePlugin addPayment:result:]':
payments.add(SKPaymentWrapper.fromJson(call.arguments));
return Future<void>.sync(() {});