diff --git a/packages/in_app_purchase/in_app_purchase_ios/README.md b/packages/in_app_purchase/in_app_purchase_ios/README.md index 025ed36b72a6..3ab033849f39 100644 --- a/packages/in_app_purchase/in_app_purchase_ios/README.md +++ b/packages/in_app_purchase/in_app_purchase_ios/README.md @@ -31,4 +31,7 @@ dependencies: ... ``` +## TODO +- [ ] Add an example application demonstrating the use of the [in_app_purchase_ios] package (see also issue [flutter/flutter#81695](https://github.com/flutter/flutter/issues/81695)). + [1]: ../in_app_purchase/in_app_purchase \ No newline at end of file diff --git a/packages/in_app_purchase/in_app_purchase_ios/lib/src/in_app_purchase_ios_platform.dart b/packages/in_app_purchase/in_app_purchase_ios/lib/src/in_app_purchase_ios_platform.dart index bb2fd2b3639a..5a2c40821007 100644 --- a/packages/in_app_purchase/in_app_purchase_ios/lib/src/in_app_purchase_ios_platform.dart +++ b/packages/in_app_purchase/in_app_purchase_ios/lib/src/in_app_purchase_ios_platform.dart @@ -23,10 +23,6 @@ const String kIAPSource = 'app_store'; /// This translates various `StoreKit` calls and responses into the /// generic plugin API. class InAppPurchaseIosPlatform extends InAppPurchasePlatform { - /// Returns the singleton instance of the [InAppPurchaseIosPlatform] that should be - /// used across the app. - static InAppPurchaseIosPlatform get instance => _getOrCreateInstance(); - static InAppPurchaseIosPlatform? _instance; static late SKPaymentQueueWrapper _skPaymentQueueWrapper; static late _TransactionObserver _observer; @@ -44,22 +40,19 @@ class InAppPurchaseIosPlatform extends InAppPurchasePlatform { @visibleForTesting static SKTransactionObserverWrapper get observer => _observer; - static InAppPurchaseIosPlatform _getOrCreateInstance() { - if (_instance != null) { - return _instance!; - } - + /// Registers this class as the default instance of [InAppPurchasePlatform]. + static void registerPlatform() { // Register the [InAppPurchaseIosPlatformAddition] containing iOS // platform-specific functionality. InAppPurchasePlatformAddition.instance = InAppPurchaseIosPlatformAddition(); // Register the platform-specific implementation of the idiomatic // InAppPurchase API. - _instance = InAppPurchaseIosPlatform(); + InAppPurchasePlatform.setInstance(InAppPurchaseIosPlatform()); + _skPaymentQueueWrapper = SKPaymentQueueWrapper(); _observer = _TransactionObserver(StreamController.broadcast()); _skPaymentQueueWrapper.setTransactionObserver(observer); - return _instance!; } @override diff --git a/packages/in_app_purchase/in_app_purchase_ios/test/in_app_purchase_ios_platform_test.dart b/packages/in_app_purchase/in_app_purchase_ios/test/in_app_purchase_ios_platform_test.dart index a70e2d9191bb..b15249c81947 100644 --- a/packages/in_app_purchase/in_app_purchase_ios/test/in_app_purchase_ios_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_ios/test/in_app_purchase_ios_platform_test.dart @@ -18,19 +18,24 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); final FakeIOSPlatform fakeIOSPlatform = FakeIOSPlatform(); + late InAppPurchaseIosPlatform iapIosPlatform; setUpAll(() { SystemChannels.platform .setMockMethodCallHandler(fakeIOSPlatform.onMethodCall); }); - setUp(() => fakeIOSPlatform.reset()); + setUp(() { + InAppPurchaseIosPlatform.registerPlatform(); + iapIosPlatform = InAppPurchasePlatform.instance as InAppPurchaseIosPlatform; + fakeIOSPlatform.reset(); + }); tearDown(() => fakeIOSPlatform.reset()); group('isAvailable', () { test('true', () async { - expect(await InAppPurchaseIosPlatform.instance.isAvailable(), isTrue); + expect(await iapIosPlatform.isAvailable(), isTrue); }); }); @@ -69,8 +74,7 @@ void main() { group('restore purchases', () { test('should emit restored transactions on purchase stream', () async { Completer completer = Completer(); - Stream> stream = - InAppPurchaseIosPlatform.instance.purchaseStream; + Stream> stream = iapIosPlatform.purchaseStream; late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { @@ -80,7 +84,7 @@ void main() { } }); - await InAppPurchaseIosPlatform.instance.restorePurchases(); + await iapIosPlatform.restorePurchases(); List details = await completer.future; expect(details.length, 2); @@ -103,8 +107,7 @@ void main() { fakeIOSPlatform.transactions .insert(0, fakeIOSPlatform.createPurchasedTransaction('foo', 'bar')); Completer completer = Completer(); - Stream> stream = - InAppPurchaseIosPlatform.instance.purchaseStream; + Stream> stream = iapIosPlatform.purchaseStream; late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { @@ -113,7 +116,7 @@ void main() { subscription.cancel(); } }); - await InAppPurchaseIosPlatform.instance.restorePurchases(); + await iapIosPlatform.restorePurchases(); List details = await completer.future; expect(details.length, 3); for (int i = 0; i < fakeIOSPlatform.transactions.length; i++) { @@ -139,8 +142,7 @@ void main() { () async { fakeIOSPlatform.receiptData = null; Completer completer = Completer(); - Stream> stream = - InAppPurchaseIosPlatform.instance.purchaseStream; + Stream> stream = iapIosPlatform.purchaseStream; late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { @@ -150,7 +152,7 @@ void main() { } }); - await InAppPurchaseIosPlatform.instance.restorePurchases(); + await iapIosPlatform.restorePurchases(); List details = await completer.future; for (PurchaseDetails purchase in details) { @@ -166,7 +168,7 @@ void main() { userInfo: {'message': 'errorMessage'}); expect( - () => InAppPurchaseIosPlatform.instance.restorePurchases(), + () => iapIosPlatform.restorePurchases(), throwsA( isA() .having((error) => error.code, 'code', 123) @@ -183,8 +185,7 @@ void main() { () async { List details = []; Completer completer = Completer(); - Stream> stream = - InAppPurchaseIosPlatform.instance.purchaseStream; + Stream> stream = iapIosPlatform.purchaseStream; late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { @@ -198,8 +199,7 @@ void main() { productDetails: AppStoreProductDetails.fromSKProduct(dummyProductWrapper), applicationUserName: 'appName'); - await InAppPurchaseIosPlatform.instance - .buyNonConsumable(purchaseParam: purchaseParam); + await iapIosPlatform.buyNonConsumable(purchaseParam: purchaseParam); List result = await completer.future; expect(result.length, 2); @@ -211,8 +211,7 @@ void main() { () async { List details = []; Completer completer = Completer(); - Stream> stream = - InAppPurchaseIosPlatform.instance.purchaseStream; + Stream> stream = iapIosPlatform.purchaseStream; late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { @@ -226,8 +225,7 @@ void main() { productDetails: AppStoreProductDetails.fromSKProduct(dummyProductWrapper), applicationUserName: 'appName'); - await InAppPurchaseIosPlatform.instance - .buyConsumable(purchaseParam: purchaseParam); + await iapIosPlatform.buyConsumable(purchaseParam: purchaseParam); List result = await completer.future; expect(result.length, 2); @@ -240,8 +238,8 @@ void main() { AppStoreProductDetails.fromSKProduct(dummyProductWrapper), applicationUserName: 'appName'); expect( - () => InAppPurchaseIosPlatform.instance - .buyConsumable(purchaseParam: purchaseParam, autoConsume: false), + () => iapIosPlatform.buyConsumable( + purchaseParam: purchaseParam, autoConsume: false), throwsA(isInstanceOf())); }); @@ -251,8 +249,7 @@ void main() { Completer completer = Completer(); late IAPError error; - Stream> stream = - InAppPurchaseIosPlatform.instance.purchaseStream; + Stream> stream = iapIosPlatform.purchaseStream; late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { details.addAll(purchaseDetailsList); @@ -268,8 +265,7 @@ void main() { productDetails: AppStoreProductDetails.fromSKProduct(dummyProductWrapper), applicationUserName: 'appName'); - await InAppPurchaseIosPlatform.instance - .buyNonConsumable(purchaseParam: purchaseParam); + await iapIosPlatform.buyNonConsumable(purchaseParam: purchaseParam); IAPError completerError = await completer.future; expect(completerError.code, 'purchase_error'); @@ -283,14 +279,13 @@ void main() { test('should complete purchase', () async { List details = []; Completer completer = Completer(); - Stream> stream = - InAppPurchaseIosPlatform.instance.purchaseStream; + Stream> stream = iapIosPlatform.purchaseStream; late StreamSubscription subscription; subscription = stream.listen((purchaseDetailsList) { details.addAll(purchaseDetailsList); purchaseDetailsList.forEach((purchaseDetails) { if (purchaseDetails.pendingCompletePurchase) { - InAppPurchaseIosPlatform.instance.completePurchase(purchaseDetails); + iapIosPlatform.completePurchase(purchaseDetails); completer.complete(details); subscription.cancel(); } @@ -300,8 +295,7 @@ void main() { productDetails: AppStoreProductDetails.fromSKProduct(dummyProductWrapper), applicationUserName: 'appName'); - await InAppPurchaseIosPlatform.instance - .buyNonConsumable(purchaseParam: purchaseParam); + await iapIosPlatform.buyNonConsumable(purchaseParam: purchaseParam); List result = await completer.future; expect(result.length, 2); expect(result.first.productID, dummyProductWrapper.productIdentifier);