[in_app_purchase] Implement registerPlatform method for iOS implementation (#3851)
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 025ed36..3ab0338 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 @@
...
```
+## 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 bb2fd2b..5a2c408 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 @@
/// 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 @@
@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 a70e2d9..b15249c 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 @@
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 @@
group('restore purchases', () {
test('should emit restored transactions on purchase stream', () async {
Completer completer = Completer();
- Stream<List<PurchaseDetails>> stream =
- InAppPurchaseIosPlatform.instance.purchaseStream;
+ Stream<List<PurchaseDetails>> stream = iapIosPlatform.purchaseStream;
late StreamSubscription subscription;
subscription = stream.listen((purchaseDetailsList) {
@@ -80,7 +84,7 @@
}
});
- await InAppPurchaseIosPlatform.instance.restorePurchases();
+ await iapIosPlatform.restorePurchases();
List<PurchaseDetails> details = await completer.future;
expect(details.length, 2);
@@ -103,8 +107,7 @@
fakeIOSPlatform.transactions
.insert(0, fakeIOSPlatform.createPurchasedTransaction('foo', 'bar'));
Completer completer = Completer();
- Stream<List<PurchaseDetails>> stream =
- InAppPurchaseIosPlatform.instance.purchaseStream;
+ Stream<List<PurchaseDetails>> stream = iapIosPlatform.purchaseStream;
late StreamSubscription subscription;
subscription = stream.listen((purchaseDetailsList) {
@@ -113,7 +116,7 @@
subscription.cancel();
}
});
- await InAppPurchaseIosPlatform.instance.restorePurchases();
+ await iapIosPlatform.restorePurchases();
List<PurchaseDetails> details = await completer.future;
expect(details.length, 3);
for (int i = 0; i < fakeIOSPlatform.transactions.length; i++) {
@@ -139,8 +142,7 @@
() async {
fakeIOSPlatform.receiptData = null;
Completer completer = Completer();
- Stream<List<PurchaseDetails>> stream =
- InAppPurchaseIosPlatform.instance.purchaseStream;
+ Stream<List<PurchaseDetails>> stream = iapIosPlatform.purchaseStream;
late StreamSubscription subscription;
subscription = stream.listen((purchaseDetailsList) {
@@ -150,7 +152,7 @@
}
});
- await InAppPurchaseIosPlatform.instance.restorePurchases();
+ await iapIosPlatform.restorePurchases();
List<PurchaseDetails> details = await completer.future;
for (PurchaseDetails purchase in details) {
@@ -166,7 +168,7 @@
userInfo: {'message': 'errorMessage'});
expect(
- () => InAppPurchaseIosPlatform.instance.restorePurchases(),
+ () => iapIosPlatform.restorePurchases(),
throwsA(
isA<SKError>()
.having((error) => error.code, 'code', 123)
@@ -183,8 +185,7 @@
() async {
List<PurchaseDetails> details = [];
Completer completer = Completer();
- Stream<List<PurchaseDetails>> stream =
- InAppPurchaseIosPlatform.instance.purchaseStream;
+ Stream<List<PurchaseDetails>> stream = iapIosPlatform.purchaseStream;
late StreamSubscription subscription;
subscription = stream.listen((purchaseDetailsList) {
@@ -198,8 +199,7 @@
productDetails:
AppStoreProductDetails.fromSKProduct(dummyProductWrapper),
applicationUserName: 'appName');
- await InAppPurchaseIosPlatform.instance
- .buyNonConsumable(purchaseParam: purchaseParam);
+ await iapIosPlatform.buyNonConsumable(purchaseParam: purchaseParam);
List<PurchaseDetails> result = await completer.future;
expect(result.length, 2);
@@ -211,8 +211,7 @@
() async {
List<PurchaseDetails> details = [];
Completer completer = Completer();
- Stream<List<PurchaseDetails>> stream =
- InAppPurchaseIosPlatform.instance.purchaseStream;
+ Stream<List<PurchaseDetails>> stream = iapIosPlatform.purchaseStream;
late StreamSubscription subscription;
subscription = stream.listen((purchaseDetailsList) {
@@ -226,8 +225,7 @@
productDetails:
AppStoreProductDetails.fromSKProduct(dummyProductWrapper),
applicationUserName: 'appName');
- await InAppPurchaseIosPlatform.instance
- .buyConsumable(purchaseParam: purchaseParam);
+ await iapIosPlatform.buyConsumable(purchaseParam: purchaseParam);
List<PurchaseDetails> result = await completer.future;
expect(result.length, 2);
@@ -240,8 +238,8 @@
AppStoreProductDetails.fromSKProduct(dummyProductWrapper),
applicationUserName: 'appName');
expect(
- () => InAppPurchaseIosPlatform.instance
- .buyConsumable(purchaseParam: purchaseParam, autoConsume: false),
+ () => iapIosPlatform.buyConsumable(
+ purchaseParam: purchaseParam, autoConsume: false),
throwsA(isInstanceOf<AssertionError>()));
});
@@ -251,8 +249,7 @@
Completer completer = Completer();
late IAPError error;
- Stream<List<PurchaseDetails>> stream =
- InAppPurchaseIosPlatform.instance.purchaseStream;
+ Stream<List<PurchaseDetails>> stream = iapIosPlatform.purchaseStream;
late StreamSubscription subscription;
subscription = stream.listen((purchaseDetailsList) {
details.addAll(purchaseDetailsList);
@@ -268,8 +265,7 @@
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 @@
test('should complete purchase', () async {
List<PurchaseDetails> details = [];
Completer completer = Completer();
- Stream<List<PurchaseDetails>> stream =
- InAppPurchaseIosPlatform.instance.purchaseStream;
+ Stream<List<PurchaseDetails>> 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 @@
productDetails:
AppStoreProductDetails.fromSKProduct(dummyProductWrapper),
applicationUserName: 'appName');
- await InAppPurchaseIosPlatform.instance
- .buyNonConsumable(purchaseParam: purchaseParam);
+ await iapIosPlatform.buyNonConsumable(purchaseParam: purchaseParam);
List<PurchaseDetails> result = await completer.future;
expect(result.length, 2);
expect(result.first.productID, dummyProductWrapper.productIdentifier);