From d39bb5a37653338fc863383b59069503442f605c Mon Sep 17 00:00:00 2001 From: yijiexu Date: Tue, 16 Jun 2020 19:17:59 -0700 Subject: [PATCH 01/13] Allow all transactions except for purchasing ones to be passed back to the Flutter side. --- .../ios/Classes/FIAPaymentQueueHandler.m | 6 ++---- .../in_app_purchase/ios/Tests/PaymentQueueTest.m | 6 +++++- packages/in_app_purchase/ios/Tests/Stubs.m | 14 ++++++++++++-- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m index 8bdb7f25f111..f5210ed6ff1b 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m +++ b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m @@ -75,7 +75,7 @@ - (void)restoreTransactions:(nullable NSString *)applicationName { - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { for (SKPaymentTransaction *transaction in transactions) { - if (transaction.transactionIdentifier) { + if (transaction.state != SKPaymentTransactionStatePurchasing) { // Use product identifier instead of transaction identifier for few reasons: // 1. Only transactions with purchased state and failed state will have a transaction id, it // will become impossible for clients to finish deferred transactions when needed. @@ -92,9 +92,7 @@ - (void)paymentQueue:(SKPaymentQueue *)queue - (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions { for (SKPaymentTransaction *transaction in transactions) { - if (transaction.transactionIdentifier) { - [self.transactionsSetter removeObjectForKey:transaction.payment.productIdentifier]; - } + [self.transactionsSetter removeObjectForKey:transaction.payment.productIdentifier]; } self.transactionsRemoved(transactions); } diff --git a/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m b/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m index 2085ba328140..92be9e3253ed 100644 --- a/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m +++ b/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m @@ -66,6 +66,7 @@ - (void)testTransactionPurchased { [handler addPayment:payment]; [self waitForExpectations:@[ expectation ] timeout:5]; XCTAssertEqual(tran.transactionState, SKPaymentTransactionStatePurchased); + XCTAssertEqual(tran.transactionIdentifier, @"fakeID"); } - (void)testDuplicateTransactionsWillTriggerAnError { @@ -113,6 +114,7 @@ - (void)testTransactionFailed { [handler addPayment:payment]; [self waitForExpectations:@[ expectation ] timeout:5]; XCTAssertEqual(tran.transactionState, SKPaymentTransactionStateFailed); + XCTAssertEqual(tran.transactionIdentifier, nil); } - (void)testTransactionRestored { @@ -140,6 +142,7 @@ - (void)testTransactionRestored { [handler addPayment:payment]; [self waitForExpectations:@[ expectation ] timeout:5]; XCTAssertEqual(tran.transactionState, SKPaymentTransactionStateRestored); + XCTAssertEqual(tran.transactionIdentifier, @"fakeID"); } - (void)testTransactionPurchasing { @@ -166,7 +169,7 @@ - (void)testTransactionPurchasing { [SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]]; [handler addPayment:payment]; [self waitForExpectations:@[ expectation ] timeout:5]; - XCTAssertEqual(tran.transactionState, SKPaymentTransactionStatePurchasing); + XCTAssertEqual(tran, nil); } - (void)testTransactionDeferred { @@ -194,6 +197,7 @@ - (void)testTransactionDeferred { [handler addPayment:payment]; [self waitForExpectations:@[ expectation ] timeout:5]; XCTAssertEqual(tran.transactionState, SKPaymentTransactionStateDeferred); + XCTAssertEqual(tran.transactionIdentifier, nil); } - (void)testFinishTransaction { diff --git a/packages/in_app_purchase/ios/Tests/Stubs.m b/packages/in_app_purchase/ios/Tests/Stubs.m index 2c3460f17f4b..271c6bf1c28a 100644 --- a/packages/in_app_purchase/ios/Tests/Stubs.m +++ b/packages/in_app_purchase/ios/Tests/Stubs.m @@ -215,7 +215,12 @@ - (instancetype)initWithMap:(NSDictionary *)map { - (instancetype)initWithState:(SKPaymentTransactionState)state { self = [super init]; if (self) { - [self setValue:@"fakeID" forKey:@"transactionIdentifier"]; + // Only purchased and restored transactions have transactionIdentifier: + //https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411288-transactionidentifier?language=objc + if (state == SKPaymentTransactionStatePurchased || + state == SKPaymentTransactionStateRestored) { + [self setValue:@"fakeID" forKey:@"transactionIdentifier"]; + } [self setValue:@(state) forKey:@"transactionState"]; } return self; @@ -224,7 +229,12 @@ - (instancetype)initWithState:(SKPaymentTransactionState)state { - (instancetype)initWithState:(SKPaymentTransactionState)state payment:(SKPayment *)payment { self = [super init]; if (self) { - [self setValue:@"fakeID" forKey:@"transactionIdentifier"]; + // Only purchased and restored transactions have transactionIdentifier: + //https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411288-transactionidentifier?language=objc + if (state == SKPaymentTransactionStatePurchased || + state == SKPaymentTransactionStateRestored) { + [self setValue:@"fakeID" forKey:@"transactionIdentifier"]; + } [self setValue:@(state) forKey:@"transactionState"]; _payment = payment; } From a0dc3848e1f71aeab849fc7f3eb704001b70aafb Mon Sep 17 00:00:00 2001 From: yijiexu Date: Tue, 16 Jun 2020 21:08:25 -0700 Subject: [PATCH 02/13] Restore transactions shouldn't block transaction updates --- .../ios/Classes/FLTConnectivityPlugin.m | 4 +++- packages/in_app_purchase/ios/Tests/Stubs.m | 10 ++++---- .../in_app_purchase/app_store_connection.dart | 10 ++++---- .../in_app_purchase_connection.dart | 8 ++++--- .../app_store_connection_test.dart | 23 +++++++++++++++++-- .../sk_test_stub_objects.dart | 1 + 6 files changed, 40 insertions(+), 16 deletions(-) diff --git a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m index 526bee25d561..0a65409b3828 100644 --- a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m +++ b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m @@ -156,7 +156,9 @@ - (NSString*)convertCLAuthorizationStatusToString:(CLAuthorizationStatus)status case kCLAuthorizationStatusAuthorizedWhenInUse: { return @"authorizedWhenInUse"; } - default: { return @"unknown"; } + default: { + return @"unknown"; + } } } diff --git a/packages/in_app_purchase/ios/Tests/Stubs.m b/packages/in_app_purchase/ios/Tests/Stubs.m index 271c6bf1c28a..58b77c14127d 100644 --- a/packages/in_app_purchase/ios/Tests/Stubs.m +++ b/packages/in_app_purchase/ios/Tests/Stubs.m @@ -216,9 +216,8 @@ - (instancetype)initWithState:(SKPaymentTransactionState)state { self = [super init]; if (self) { // Only purchased and restored transactions have transactionIdentifier: - //https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411288-transactionidentifier?language=objc - if (state == SKPaymentTransactionStatePurchased || - state == SKPaymentTransactionStateRestored) { + // https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411288-transactionidentifier?language=objc + if (state == SKPaymentTransactionStatePurchased || state == SKPaymentTransactionStateRestored) { [self setValue:@"fakeID" forKey:@"transactionIdentifier"]; } [self setValue:@(state) forKey:@"transactionState"]; @@ -230,9 +229,8 @@ - (instancetype)initWithState:(SKPaymentTransactionState)state payment:(SKPaymen self = [super init]; if (self) { // Only purchased and restored transactions have transactionIdentifier: - //https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411288-transactionidentifier?language=objc - if (state == SKPaymentTransactionStatePurchased || - state == SKPaymentTransactionStateRestored) { + // https://developer.apple.com/documentation/storekit/skpaymenttransaction/1411288-transactionidentifier?language=objc + if (state == SKPaymentTransactionStatePurchased || state == SKPaymentTransactionStateRestored) { [self setValue:@"fakeID" forKey:@"transactionIdentifier"]; } [self setValue:@(state) forKey:@"transactionState"]; diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index 871879dca08e..cf711aaa4839 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -18,7 +18,7 @@ import '../../billing_client_wrappers.dart'; /// This translates various `StoreKit` calls and responses into the /// generic plugin API. class AppStoreConnection implements InAppPurchaseConnection { - static AppStoreConnection get instance => _getOrCreateInstance(); + static AppStoreConnection get instance => getOrCreateInstance(); static AppStoreConnection _instance; static SKPaymentQueueWrapper _skPaymentQueueWrapper; static _TransactionObserver _observer; @@ -28,7 +28,7 @@ class AppStoreConnection implements InAppPurchaseConnection { static SKTransactionObserverWrapper get observer => _observer; - static AppStoreConnection _getOrCreateInstance() { + static AppStoreConnection getOrCreateInstance() { if (_instance != null) { return _instance; } @@ -208,12 +208,14 @@ class _TransactionObserver implements SKTransactionObserverWrapper { return wrapper.transactionState == SKPaymentTransactionStateWrapper.restored; }).map((SKPaymentTransactionWrapper wrapper) => wrapper)); - return; } String receiptData = await getReceiptData(); purchaseUpdatedController - .add(transactions.map((SKPaymentTransactionWrapper transaction) { + .add(transactions.where((SKPaymentTransactionWrapper wrapper) { + return wrapper.transactionState != + SKPaymentTransactionStateWrapper.restored; + }).map((SKPaymentTransactionWrapper transaction) { PurchaseDetails purchaseDetails = PurchaseDetails.fromSKTransaction(transaction, receiptData); return purchaseDetails; diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart index 2079f69dce6c..6196a39d67ea 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart @@ -71,15 +71,17 @@ abstract class InAppPurchaseConnection { /// Enable the [InAppPurchaseConnection] to handle pending purchases. /// - /// Android Only: This method is required to be called when initialize the application. + /// This method is required to be called when initialize the application. /// It is to acknowledge your application has been updated to support pending purchases. /// See [Support pending transactions](https://developer.android.com/google/play/billing/billing_library_overview#pending) /// for more details. /// Failure to call this method before access [instance] will throw an exception. - /// - /// It is an no-op on iOS. static void enablePendingPurchases() { _enablePendingPurchase = true; + if (Platform.isIOS) { + // Setting setTransactionObserver to prevent throwing exceptions. + AppStoreConnection.getOrCreateInstance(); + } } /// Query product details for the given set of IDs. diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index cb2e0e7cad56..f695d791eecc 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -90,6 +90,27 @@ void main() { expect(response.error, isNull); }); + test('queryPastPurchases should not block transaction updates', () async { + fakeIOSPlatform.transactions.add(fakeIOSPlatform.createPurchasedTransactionWithProductID('foo')); + Completer completer = Completer(); + Stream> stream = + AppStoreConnection.instance.purchaseUpdatedStream; + + StreamSubscription subscription; + subscription = stream.listen((purchaseDetailsList) { + if (purchaseDetailsList.first.status == PurchaseStatus.purchased) { + completer.complete(purchaseDetailsList); + subscription.cancel(); + } + }); + QueryPurchaseDetailsResponse response = + await AppStoreConnection.instance.queryPastPurchases(); + List result = await completer.future; + expect(result.length, 1); + expect(result.first.productID, 'foo'); + expect(response.error, isNull); + }); + test('should get empty result if there is no restored transactions', () async { fakeIOSPlatform.testRestoredTransactionsNull = true; @@ -331,7 +352,6 @@ class FakeIOSPlatform { payment: SKPaymentWrapper(productIdentifier: id), transactionState: SKPaymentTransactionStateWrapper.purchasing, transactionTimeStamp: 123123.121, - transactionIdentifier: id, error: null, originalTransaction: null); } @@ -352,7 +372,6 @@ class FakeIOSPlatform { payment: SKPaymentWrapper(productIdentifier: id), transactionState: SKPaymentTransactionStateWrapper.failed, transactionTimeStamp: 123123.121, - transactionIdentifier: id, error: SKError( code: 0, domain: 'ios_domain', diff --git a/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart b/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart index 1dc70748f1db..c976e80a90a5 100644 --- a/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart +++ b/packages/in_app_purchase/test/store_kit_wrappers/sk_test_stub_objects.dart @@ -22,6 +22,7 @@ final SKPaymentTransactionWrapper dummyOriginalTransaction = transactionIdentifier: '123123', error: dummyError, ); + final SKPaymentTransactionWrapper dummyTransaction = SKPaymentTransactionWrapper( transactionState: SKPaymentTransactionStateWrapper.purchased, From 2636df9891b9cc3f8a7f34855fe2eaa48919d9dd Mon Sep 17 00:00:00 2001 From: yijiexu Date: Tue, 16 Jun 2020 21:13:44 -0700 Subject: [PATCH 03/13] Apply formatting --- .../lib/src/in_app_purchase/app_store_connection.dart | 6 +++--- .../lib/src/in_app_purchase/in_app_purchase_connection.dart | 2 +- .../app_store_connection_test.dart | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index cf711aaa4839..7b96aa42585a 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -213,9 +213,9 @@ class _TransactionObserver implements SKTransactionObserverWrapper { String receiptData = await getReceiptData(); purchaseUpdatedController .add(transactions.where((SKPaymentTransactionWrapper wrapper) { - return wrapper.transactionState != - SKPaymentTransactionStateWrapper.restored; - }).map((SKPaymentTransactionWrapper transaction) { + return wrapper.transactionState != + SKPaymentTransactionStateWrapper.restored; + }).map((SKPaymentTransactionWrapper transaction) { PurchaseDetails purchaseDetails = PurchaseDetails.fromSKTransaction(transaction, receiptData); return purchaseDetails; diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart index 6196a39d67ea..f452c330de37 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart @@ -79,7 +79,7 @@ abstract class InAppPurchaseConnection { static void enablePendingPurchases() { _enablePendingPurchase = true; if (Platform.isIOS) { - // Setting setTransactionObserver to prevent throwing exceptions. + // Setting setTransactionObserver to prevent throwing exceptions. AppStoreConnection.getOrCreateInstance(); } } diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index f695d791eecc..d820edf82b8d 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -91,7 +91,8 @@ void main() { }); test('queryPastPurchases should not block transaction updates', () async { - fakeIOSPlatform.transactions.add(fakeIOSPlatform.createPurchasedTransactionWithProductID('foo')); + fakeIOSPlatform.transactions + .add(fakeIOSPlatform.createPurchasedTransactionWithProductID('foo')); Completer completer = Completer(); Stream> stream = AppStoreConnection.instance.purchaseUpdatedStream; From d27e08c948e8124c802ba77f6cde3bbe590c0c21 Mon Sep 17 00:00:00 2001 From: yijiexu Date: Tue, 16 Jun 2020 21:17:42 -0700 Subject: [PATCH 04/13] Updated pubspec and changelog --- packages/in_app_purchase/CHANGELOG.md | 5 +++++ packages/in_app_purchase/pubspec.yaml | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index b7b025cbef6f..1e7c398a5e6b 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,3 +1,8 @@ +## 0.3.5 + +* Fix the bug that `SKPaymentQueueWrapper.transactions` doesn't return all transactions. +* `enablePendingPurchases` now works on iOS too. + ## 0.3.4 * Expose SKError code to client apps. diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index 12c7b45f7ddf..add416393331 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.4 +version: 0.3.5 dependencies: async: ^2.0.8 From 8de3f405d97a059188d8a2a633f45f6683c28c40 Mon Sep 17 00:00:00 2001 From: yijiexu Date: Tue, 16 Jun 2020 21:40:32 -0700 Subject: [PATCH 05/13] Fix build error --- packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m index f5210ed6ff1b..57370e16fcbb 100644 --- a/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m +++ b/packages/in_app_purchase/ios/Classes/FIAPaymentQueueHandler.m @@ -75,7 +75,7 @@ - (void)restoreTransactions:(nullable NSString *)applicationName { - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions { for (SKPaymentTransaction *transaction in transactions) { - if (transaction.state != SKPaymentTransactionStatePurchasing) { + if (transaction.transactionState != SKPaymentTransactionStatePurchasing) { // Use product identifier instead of transaction identifier for few reasons: // 1. Only transactions with purchased state and failed state will have a transaction id, it // will become impossible for clients to finish deferred transactions when needed. From b0c036f96f2d337575070508de453086d6d67cf2 Mon Sep 17 00:00:00 2001 From: yijiexu Date: Tue, 16 Jun 2020 22:14:09 -0700 Subject: [PATCH 06/13] Fix test error --- packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m index e6a18e0acf58..20543a203a97 100644 --- a/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m +++ b/packages/in_app_purchase/ios/Tests/InAppPurchasePluginTest.m @@ -121,6 +121,7 @@ - (void)testAddPaymentWithSameProductIDWillFail { @"simulatesAskToBuyInSandBox" : @YES, }]; SKPaymentQueueStub* queue = [SKPaymentQueueStub new]; + queue.testState = SKPaymentTransactionStatePurchased; self.plugin.paymentQueueHandler = [[FIAPaymentQueueHandler alloc] initWithQueue:queue transactionsUpdated:^(NSArray* _Nonnull transactions) { } From e1025fc0eedfd1fd31cfc3697247118af674015b Mon Sep 17 00:00:00 2001 From: yijiexu Date: Tue, 16 Jun 2020 22:32:38 -0700 Subject: [PATCH 07/13] fix test error --- packages/in_app_purchase/ios/Tests/PaymentQueueTest.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m b/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m index 92be9e3253ed..8f5b66496f69 100644 --- a/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m +++ b/packages/in_app_purchase/ios/Tests/PaymentQueueTest.m @@ -169,7 +169,8 @@ - (void)testTransactionPurchasing { [SKPayment paymentWithProduct:[[SKProductStub alloc] initWithMap:self.productResponseMap]]; [handler addPayment:payment]; [self waitForExpectations:@[ expectation ] timeout:5]; - XCTAssertEqual(tran, nil); + XCTAssertEqual(tran.transactionState, SKPaymentTransactionStatePurchasing); + XCTAssertEqual(tran.transactionIdentifier, nil); } - (void)testTransactionDeferred { From e4d1646c4f40663baa5c09550c7949cd120fc64c Mon Sep 17 00:00:00 2001 From: yijiexu Date: Tue, 16 Jun 2020 22:55:01 -0700 Subject: [PATCH 08/13] Fix analyze error --- .../in_app_purchase_connection/app_store_connection_test.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart index d820edf82b8d..881e1fcc75b7 100644 --- a/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart +++ b/packages/in_app_purchase/test/in_app_purchase_connection/app_store_connection_test.dart @@ -350,6 +350,7 @@ class FakeIOSPlatform { SKPaymentTransactionWrapper createPendingTransactionWithProductID(String id) { return SKPaymentTransactionWrapper( + transactionIdentifier: null, payment: SKPaymentWrapper(productIdentifier: id), transactionState: SKPaymentTransactionStateWrapper.purchasing, transactionTimeStamp: 123123.121, @@ -370,6 +371,7 @@ class FakeIOSPlatform { SKPaymentTransactionWrapper createFailedTransactionWithProductID(String id) { return SKPaymentTransactionWrapper( + transactionIdentifier: null, payment: SKPaymentWrapper(productIdentifier: id), transactionState: SKPaymentTransactionStateWrapper.failed, transactionTimeStamp: 123123.121, From 163c1edd72572acfdc49d6f28a063b73958893b6 Mon Sep 17 00:00:00 2001 From: yijiexu Date: Fri, 19 Jun 2020 11:18:05 -0700 Subject: [PATCH 09/13] Fix assertion error --- .../connectivity/ios/Classes/FLTConnectivityPlugin.m | 4 +--- .../lib/src/in_app_purchase/app_store_connection.dart | 4 ++-- .../lib/src/in_app_purchase/in_app_purchase_connection.dart | 6 ++---- .../src/store_kit_wrappers/sk_payment_queue_wrapper.dart | 5 ++--- 4 files changed, 7 insertions(+), 12 deletions(-) diff --git a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m index 0a65409b3828..526bee25d561 100644 --- a/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m +++ b/packages/connectivity/connectivity/ios/Classes/FLTConnectivityPlugin.m @@ -156,9 +156,7 @@ - (NSString*)convertCLAuthorizationStatusToString:(CLAuthorizationStatus)status case kCLAuthorizationStatusAuthorizedWhenInUse: { return @"authorizedWhenInUse"; } - default: { - return @"unknown"; - } + default: { return @"unknown"; } } } diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart index 7b96aa42585a..da6fc7417585 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/app_store_connection.dart @@ -18,7 +18,7 @@ import '../../billing_client_wrappers.dart'; /// This translates various `StoreKit` calls and responses into the /// generic plugin API. class AppStoreConnection implements InAppPurchaseConnection { - static AppStoreConnection get instance => getOrCreateInstance(); + static AppStoreConnection get instance => _getOrCreateInstance(); static AppStoreConnection _instance; static SKPaymentQueueWrapper _skPaymentQueueWrapper; static _TransactionObserver _observer; @@ -28,7 +28,7 @@ class AppStoreConnection implements InAppPurchaseConnection { static SKTransactionObserverWrapper get observer => _observer; - static AppStoreConnection getOrCreateInstance() { + static AppStoreConnection _getOrCreateInstance() { if (_instance != null) { return _instance; } diff --git a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart index f452c330de37..ba3932f73878 100644 --- a/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart +++ b/packages/in_app_purchase/lib/src/in_app_purchase/in_app_purchase_connection.dart @@ -76,12 +76,10 @@ abstract class InAppPurchaseConnection { /// See [Support pending transactions](https://developer.android.com/google/play/billing/billing_library_overview#pending) /// for more details. /// Failure to call this method before access [instance] will throw an exception. + /// + /// It is an no-op on iOS. static void enablePendingPurchases() { _enablePendingPurchase = true; - if (Platform.isIOS) { - // Setting setTransactionObserver to prevent throwing exceptions. - AppStoreConnection.getOrCreateInstance(); - } } /// Query product details for the given set of IDs. 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 49c438e40231..33d9281d3ce0 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 @@ -37,9 +37,7 @@ class SKPaymentQueueWrapper { static final SKPaymentQueueWrapper _singleton = SKPaymentQueueWrapper._(); - SKPaymentQueueWrapper._() { - callbackChannel.setMethodCallHandler(_handleObserverCallbacks); - } + SKPaymentQueueWrapper._(); /// Calls [`-[SKPaymentQueue transactions]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506026-transactions?language=objc) Future> transactions() async { @@ -59,6 +57,7 @@ class SKPaymentQueueWrapper { /// addTransactionObserver:]`](https://developer.apple.com/documentation/storekit/skpaymentqueue/1506042-addtransactionobserver?language=objc). void setTransactionObserver(SKTransactionObserverWrapper observer) { _observer = observer; + callbackChannel.setMethodCallHandler(_handleObserverCallbacks); } /// Posts a payment to the queue. From 360e1b19dd2ac67a39049342fbff617970ca7385 Mon Sep 17 00:00:00 2001 From: yijiexu Date: Sun, 21 Jun 2020 13:36:37 -0700 Subject: [PATCH 10/13] Update outdated changelog --- packages/in_app_purchase/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index 1e7c398a5e6b..82db7e0986b5 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,7 +1,7 @@ -## 0.3.5 +## 0.3.4+1 * Fix the bug that `SKPaymentQueueWrapper.transactions` doesn't return all transactions. -* `enablePendingPurchases` now works on iOS too. +* Fix the app crashes if `queryPastPurchases` is called in the `main()`. ## 0.3.4 From 35b30a9975b082f3b34d16acb483232683e1e5de Mon Sep 17 00:00:00 2001 From: yijiexu Date: Mon, 22 Jun 2020 09:38:46 -0700 Subject: [PATCH 11/13] Update changelog wording --- packages/in_app_purchase/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index 82db7e0986b5..caa82191bbde 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,7 +1,7 @@ ## 0.3.4+1 -* Fix the bug that `SKPaymentQueueWrapper.transactions` doesn't return all transactions. -* Fix the app crashes if `queryPastPurchases` is called in the `main()`. +* iOS: Fix the bug that `SKPaymentQueueWrapper.transactions` doesn't return all transactions. +* iOS: Fix the app crashes if `queryPastPurchases` is called in the `main()`. ## 0.3.4 From 0e4ce8c0be74e91e5040b03ccaa496d73aa2024c Mon Sep 17 00:00:00 2001 From: yijiexu Date: Mon, 22 Jun 2020 09:39:39 -0700 Subject: [PATCH 12/13] update pubspec to align with changelog --- packages/in_app_purchase/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/in_app_purchase/pubspec.yaml b/packages/in_app_purchase/pubspec.yaml index add416393331..58f8e1174618 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.5 +version: 0.3.4+1 dependencies: async: ^2.0.8 From 5be4a764fefaded1e2109a5a358d80c3f4ba1076 Mon Sep 17 00:00:00 2001 From: yijiexu Date: Mon, 22 Jun 2020 09:41:23 -0700 Subject: [PATCH 13/13] update wording --- packages/in_app_purchase/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/CHANGELOG.md index caa82191bbde..c159b094fb47 100644 --- a/packages/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/CHANGELOG.md @@ -1,7 +1,7 @@ ## 0.3.4+1 * iOS: Fix the bug that `SKPaymentQueueWrapper.transactions` doesn't return all transactions. -* iOS: Fix the app crashes if `queryPastPurchases` is called in the `main()`. +* iOS: Fix the app crashes if `InAppPurchaseConnection.instance` is called in the `main()`. ## 0.3.4