From 674bdddef029e849e60122f0de13e99fe52f0ae7 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 22 Apr 2021 10:19:19 -0700 Subject: [PATCH 1/9] platform interface improvement --- .../lib/src/in_app_purchase_platform.dart | 7 ++- .../in_app_purchase_platform_addition.dart | 35 +++++++++-- .../test/in_app_purchase_platform_test.dart | 60 +++++++++++++++++-- 3 files changed, 88 insertions(+), 14 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform.dart index f8dc4c998494..e3a99f077d8d 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform.dart @@ -24,15 +24,16 @@ abstract class InAppPurchasePlatform extends PlatformInterface { /// The instance of [InAppPurchasePlatform] to use. /// /// Defaults to `null`. - static InAppPurchasePlatform? get instance => _instance; + static InAppPurchasePlatform get instance => _instance; - static InAppPurchasePlatform? _instance; + // Should only be accessed after setter is called. + static late InAppPurchasePlatform _instance; /// Platform-specific plugins should set this with their own platform-specific /// class that extends [InAppPurchasePlatform] when they register themselves. // TODO(amirh): Extract common platform interface logic. // https://github.com/flutter/flutter/issues/43368 - static void setInstance(InAppPurchasePlatform instance) { + static set instance(InAppPurchasePlatform instance) { PlatformInterface.verifyToken(instance, _token); _instance = instance; } diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart index 5c41f138ecea..835519b2695c 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart @@ -2,10 +2,27 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ignore: avoid_classes_with_only_static_members +import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart'; +import 'package:plugin_platform_interface/plugin_platform_interface.dart'; + /// The interface that platform implementations must implement when they want to /// provide platform specific in_app_purchase features. -abstract class InAppPurchasePlatformAddition { +/// +/// Platform implementations should extend this class rather than implement it as `in_app_purchase` +/// does not consider newly added methods to be breaking changes. Extending this class +/// (using `extends`) ensures that the subclass will get the default implementation, while +/// platform implementations that `implements` this interface will be broken by newly added +/// [InAppPurchasePlatformAddition] methods. +abstract class InAppPurchasePlatformAddition extends PlatformInterface { + + /// Constructs a InAppPurchasePlatform. + InAppPurchasePlatformAddition() : super(token: _token); + + static final Object _token = Object(); + + // Should only be accessed after setter is called. + static late InAppPurchasePlatformAddition _instance; + /// The instance containing the platform-specific in_app_purchase /// functionality. /// @@ -13,7 +30,7 @@ abstract class InAppPurchasePlatformAddition { /// [`InAppPurchasePlatformAddition`][3] with the platform-specific /// functionality, and when the plugin is registered, set the /// `InAppPurchasePlatformAddition.instance` with the new addition - /// implementationinstance. + /// implementation instance. /// /// Example implementation might look like this: /// ```dart @@ -22,7 +39,7 @@ abstract class InAppPurchasePlatformAddition { /// } /// ``` /// - /// The following snippit shows how to register the `InAppPurchaseMyPlatformAddition`: + /// The following snippet shows how to register the `InAppPurchaseMyPlatformAddition`: /// ```dart /// class InAppPurchaseMyPlatformPlugin { /// static void registerWith(Registrar registrar) { @@ -36,5 +53,13 @@ abstract class InAppPurchasePlatformAddition { /// } /// } /// ``` - static InAppPurchasePlatformAddition? instance; + static InAppPurchasePlatformAddition get instance => _instance; + + /// Platform-specific plugins should set this with their own platform-specific + /// class that extends [InAppPurchasePlatformAddition] when they register themselves. + static set instance(InAppPurchasePlatformAddition instance) { + PlatformInterface.verifyToken(instance, _token); + assert(instance.runtimeType is! InAppPurchasePlatform); + _instance = instance; + } } diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart index d5c1ae5fc127..73dec75df43c 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart @@ -11,22 +11,19 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('$InAppPurchasePlatform', () { - test('Default instance should return null', () { - expect(InAppPurchasePlatform.instance, null); - }); test('Cannot be implemented with `implements`', () { expect(() { - InAppPurchasePlatform.setInstance(ImplementsInAppPurchasePlatform()); + InAppPurchasePlatform.instance = ImplementsInAppPurchasePlatform(); }, throwsNoSuchMethodError); }); test('Can be extended', () { - InAppPurchasePlatform.setInstance(ExtendsInAppPurchasePlatform()); + InAppPurchasePlatform.instance = ExtendsInAppPurchasePlatform(); }); test('Can be mocked with `implements`', () { - InAppPurchasePlatform.setInstance(MockInAppPurchasePlatform()); + InAppPurchasePlatform.instance = MockInAppPurchasePlatform(); }); test( @@ -124,6 +121,31 @@ void main() { ); }); }); + + group('$InAppPurchasePlatformAddition', () { + + test('Cannot be implemented with `implements`', () { + expect(() { + InAppPurchasePlatformAddition.instance = ImplementsInAppPurchasePlatformAddition(); + }, throwsNoSuchMethodError); + }); + + test('InAppPurchasePlatformAddition Can be extended', () { + InAppPurchasePlatformAddition.instance = ExtendsInAppPurchasePlatformAddition(); + }); + + test('Can be mocked with `implements`', () { + InAppPurchasePlatformAddition.instance = MockInAppPurchasePlatformAddition(); + }); + + test('Provider can provide', () { + ImplementsInAppPurchasePlatformAdditionProvider.register(); + final ImplementsInAppPurchasePlatformAdditionProvider provider = ImplementsInAppPurchasePlatformAdditionProvider(); + final InAppPurchasePlatformAddition addition = provider.getPlatformAddition(); + expect(addition.runtimeType, ExtendsInAppPurchasePlatformAddition); + }); + + }); } class ImplementsInAppPurchasePlatform implements InAppPurchasePlatform { @@ -143,3 +165,29 @@ class ExtendsInAppPurchasePlatform extends InAppPurchasePlatform {} class MockPurchaseParam extends Mock implements PurchaseParam {} class MockPurchaseDetails extends Mock implements PurchaseDetails {} + +class ImplementsInAppPurchasePlatformAddition implements InAppPurchasePlatformAddition { + @override + dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); +} + +class MockInAppPurchasePlatformAddition extends Mock + with + // ignore: prefer_mixin + MockPlatformInterfaceMixin + implements + InAppPurchasePlatformAddition {} + +class ExtendsInAppPurchasePlatformAddition extends InAppPurchasePlatformAddition {} + +class ImplementsInAppPurchasePlatformAdditionProvider implements InAppPurchasePlatformAdditionProvider { + + static void register() { + InAppPurchasePlatformAddition.instance = ExtendsInAppPurchasePlatformAddition(); + } + + @override + T getPlatformAddition() { + return InAppPurchasePlatformAddition.instance as T; + } +} From 875d3f1274fda7b16d0418e07cbdc27593624b7b Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Thu, 22 Apr 2021 10:27:25 -0700 Subject: [PATCH 2/9] format --- .../in_app_purchase_platform_addition.dart | 1 - .../test/in_app_purchase_platform_test.dart | 31 +++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart index 835519b2695c..77660faf4776 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart @@ -14,7 +14,6 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; /// platform implementations that `implements` this interface will be broken by newly added /// [InAppPurchasePlatformAddition] methods. abstract class InAppPurchasePlatformAddition extends PlatformInterface { - /// Constructs a InAppPurchasePlatform. InAppPurchasePlatformAddition() : super(token: _token); diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart index 73dec75df43c..7b885a3066e7 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart @@ -11,7 +11,6 @@ void main() { TestWidgetsFlutterBinding.ensureInitialized(); group('$InAppPurchasePlatform', () { - test('Cannot be implemented with `implements`', () { expect(() { InAppPurchasePlatform.instance = ImplementsInAppPurchasePlatform(); @@ -123,28 +122,31 @@ void main() { }); group('$InAppPurchasePlatformAddition', () { - test('Cannot be implemented with `implements`', () { expect(() { - InAppPurchasePlatformAddition.instance = ImplementsInAppPurchasePlatformAddition(); + InAppPurchasePlatformAddition.instance = + ImplementsInAppPurchasePlatformAddition(); }, throwsNoSuchMethodError); }); test('InAppPurchasePlatformAddition Can be extended', () { - InAppPurchasePlatformAddition.instance = ExtendsInAppPurchasePlatformAddition(); + InAppPurchasePlatformAddition.instance = + ExtendsInAppPurchasePlatformAddition(); }); test('Can be mocked with `implements`', () { - InAppPurchasePlatformAddition.instance = MockInAppPurchasePlatformAddition(); + InAppPurchasePlatformAddition.instance = + MockInAppPurchasePlatformAddition(); }); test('Provider can provide', () { ImplementsInAppPurchasePlatformAdditionProvider.register(); - final ImplementsInAppPurchasePlatformAdditionProvider provider = ImplementsInAppPurchasePlatformAdditionProvider(); - final InAppPurchasePlatformAddition addition = provider.getPlatformAddition(); + final ImplementsInAppPurchasePlatformAdditionProvider provider = + ImplementsInAppPurchasePlatformAdditionProvider(); + final InAppPurchasePlatformAddition addition = + provider.getPlatformAddition(); expect(addition.runtimeType, ExtendsInAppPurchasePlatformAddition); }); - }); } @@ -166,7 +168,8 @@ class MockPurchaseParam extends Mock implements PurchaseParam {} class MockPurchaseDetails extends Mock implements PurchaseDetails {} -class ImplementsInAppPurchasePlatformAddition implements InAppPurchasePlatformAddition { +class ImplementsInAppPurchasePlatformAddition + implements InAppPurchasePlatformAddition { @override dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); } @@ -178,12 +181,14 @@ class MockInAppPurchasePlatformAddition extends Mock implements InAppPurchasePlatformAddition {} -class ExtendsInAppPurchasePlatformAddition extends InAppPurchasePlatformAddition {} - -class ImplementsInAppPurchasePlatformAdditionProvider implements InAppPurchasePlatformAdditionProvider { +class ExtendsInAppPurchasePlatformAddition + extends InAppPurchasePlatformAddition {} +class ImplementsInAppPurchasePlatformAdditionProvider + implements InAppPurchasePlatformAdditionProvider { static void register() { - InAppPurchasePlatformAddition.instance = ExtendsInAppPurchasePlatformAddition(); + InAppPurchasePlatformAddition.instance = + ExtendsInAppPurchasePlatformAddition(); } @override From 06daea2115fb9d96da99b5403c07191488d8ef14 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Fri, 23 Apr 2021 12:30:09 -0700 Subject: [PATCH 3/9] review --- .../in_app_purchase/CHANGELOG.md | 2 +- .../src/in_app_purchase/product_details.dart | 2 +- .../lib/src/in_app_purchase_platform.dart | 10 ++++----- .../in_app_purchase_platform_addition.dart | 17 +++++++++------ ...p_purchase_platform_addition_provider.dart | 8 +++---- .../src/types/product_details_response.dart | 2 +- .../test/in_app_purchase_platform_test.dart | 21 +++++++++++++++++-- 7 files changed, 42 insertions(+), 20 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md index 5e7f54560b8c..45b8b7661203 100644 --- a/packages/in_app_purchase/in_app_purchase/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase/CHANGELOG.md @@ -354,7 +354,7 @@ Beta release. * Ability to list products, load previous purchases, and make purchases. * Simplified Dart API that's been unified for ease of use. -* Platform specific APIs more directly exposing `StoreKit` and `BillingClient`. +* Platform-specific APIs more directly exposing `StoreKit` and `BillingClient`. Includes: diff --git a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/product_details.dart b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/product_details.dart index ccdec42b7303..4ba61305e445 100644 --- a/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/product_details.dart +++ b/packages/in_app_purchase/in_app_purchase/lib/src/in_app_purchase/product_details.dart @@ -90,7 +90,7 @@ class ProductDetailsResponse { /// The list of identifiers that are in the `identifiers` of [InAppPurchaseConnection.queryProductDetails] but failed to be fetched. /// - /// There's multiple platform specific reasons that product information could fail to be fetched, + /// There's multiple platform-specific reasons that product information could fail to be fetched, /// ranging from products not being correctly configured in the storefront to the queried IDs not existing. final List notFoundIDs; diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform.dart index e3a99f077d8d..eac4a0712078 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform.dart @@ -23,12 +23,9 @@ abstract class InAppPurchasePlatform extends PlatformInterface { /// The instance of [InAppPurchasePlatform] to use. /// - /// Defaults to `null`. + /// Must be set before accessing. static InAppPurchasePlatform get instance => _instance; - // Should only be accessed after setter is called. - static late InAppPurchasePlatform _instance; - /// Platform-specific plugins should set this with their own platform-specific /// class that extends [InAppPurchasePlatform] when they register themselves. // TODO(amirh): Extract common platform interface logic. @@ -38,13 +35,16 @@ abstract class InAppPurchasePlatform extends PlatformInterface { _instance = instance; } + // Should only be accessed after setter is called. + static late InAppPurchasePlatform _instance; + /// Listen to this broadcast stream to get real time update for purchases. /// /// This stream will never close as long as the app is active. /// /// Purchase updates can happen in several situations: /// * When a purchase is triggered by user in the app. - /// * When a purchase is triggered by user from the platform specific store front. + /// * When a purchase is triggered by user from the platform-specific store front. /// * When a purchase is restored on the device by the user in the app. /// * If a purchase is not completed ([completePurchase] is not called on the /// purchase object) from the last app session. Purchase updates will happen diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart index 77660faf4776..7785c0c3a289 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart @@ -6,7 +6,7 @@ import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_inte import 'package:plugin_platform_interface/plugin_platform_interface.dart'; /// The interface that platform implementations must implement when they want to -/// provide platform specific in_app_purchase features. +/// provide platform-specific in_app_purchase features. /// /// Platform implementations should extend this class rather than implement it as `in_app_purchase` /// does not consider newly added methods to be breaking changes. Extending this class @@ -20,11 +20,13 @@ abstract class InAppPurchasePlatformAddition extends PlatformInterface { static final Object _token = Object(); // Should only be accessed after setter is called. - static late InAppPurchasePlatformAddition _instance; + static InAppPurchasePlatformAddition? _instance; /// The instance containing the platform-specific in_app_purchase /// functionality. /// + /// Returns `null` by default. + /// /// To implement additional functionality extend /// [`InAppPurchasePlatformAddition`][3] with the platform-specific /// functionality, and when the plugin is registered, set the @@ -52,13 +54,16 @@ abstract class InAppPurchasePlatformAddition extends PlatformInterface { /// } /// } /// ``` - static InAppPurchasePlatformAddition get instance => _instance; + static InAppPurchasePlatformAddition? get instance => _instance; /// Platform-specific plugins should set this with their own platform-specific /// class that extends [InAppPurchasePlatformAddition] when they register themselves. - static set instance(InAppPurchasePlatformAddition instance) { - PlatformInterface.verifyToken(instance, _token); - assert(instance.runtimeType is! InAppPurchasePlatform); + static set instance(InAppPurchasePlatformAddition? instance) { _instance = instance; + if (_instance == null) { + return; + } + PlatformInterface.verifyToken(instance!, _token); + assert(instance.runtimeType is! InAppPurchasePlatform); } } diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition_provider.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition_provider.dart index d981f73b4019..642bbb419c6e 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition_provider.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition_provider.dart @@ -5,13 +5,13 @@ import 'package:in_app_purchase_platform_interface/src/in_app_purchase_platform_addition.dart'; /// The [InAppPurchasePlatformAdditionProvider] is responsible for providing -/// a platform specific [InAppPurchasePlatformAddition]. +/// a platform-specific [InAppPurchasePlatformAddition]. /// -/// [InAppPurchasePlatformAddition] implementation contain platform specific +/// [InAppPurchasePlatformAddition] implementation contain platform-specific /// features that are not available from the platform idiomatic /// [InAppPurchasePlatform] API. abstract class InAppPurchasePlatformAdditionProvider { - /// Provides a platform specific implementation of the [InAppPurchasePlatformAddition] + /// Provides a platform-specific implementation of the [InAppPurchasePlatformAddition] /// class. - T getPlatformAddition(); + T getPlatformAddition(); } diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart index 868f9428add2..d8331d6560d8 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart @@ -18,7 +18,7 @@ class ProductDetailsResponse { /// The list of identifiers that are in the `identifiers` of [InAppPurchasePlatform.queryProductDetails] but failed to be fetched. /// - /// There's multiple platform specific reasons that product information could fail to be fetched, + /// There's multiple platform-specific reasons that product information could fail to be fetched, /// ranging from products not being correctly configured in the storefront to the queried IDs not existing. final List notFoundIDs; diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart index 7b885a3066e7..750599170990 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart @@ -122,6 +122,15 @@ void main() { }); group('$InAppPurchasePlatformAddition', () { + + setUp(() { + InAppPurchasePlatformAddition.instance = null; + }); + + test('Cannot be implemented with `implements`', () { + expect(InAppPurchasePlatformAddition.instance, isNull); + }); + test('Cannot be implemented with `implements`', () { expect(() { InAppPurchasePlatformAddition.instance = @@ -143,10 +152,18 @@ void main() { ImplementsInAppPurchasePlatformAdditionProvider.register(); final ImplementsInAppPurchasePlatformAdditionProvider provider = ImplementsInAppPurchasePlatformAdditionProvider(); - final InAppPurchasePlatformAddition addition = + final InAppPurchasePlatformAddition? addition = provider.getPlatformAddition(); expect(addition.runtimeType, ExtendsInAppPurchasePlatformAddition); }); + + test('Provider can provide `null`', () { + final ImplementsInAppPurchasePlatformAdditionProvider provider = + ImplementsInAppPurchasePlatformAdditionProvider(); + final InAppPurchasePlatformAddition? addition = + provider.getPlatformAddition(); + expect(addition, isNull); + }); }); } @@ -192,7 +209,7 @@ class ImplementsInAppPurchasePlatformAdditionProvider } @override - T getPlatformAddition() { + T getPlatformAddition() { return InAppPurchasePlatformAddition.instance as T; } } From 7f1653f98b16e2bc467a353d0ebafc3d53c05190 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 3 May 2021 10:28:56 -0700 Subject: [PATCH 4/9] review --- .../in_app_purchase_platform_addition.dart | 34 +++++-------------- .../test/in_app_purchase_platform_test.dart | 9 ++--- 2 files changed, 11 insertions(+), 32 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart index 7785c0c3a289..2d113ef4fc53 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart @@ -8,20 +8,13 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; /// The interface that platform implementations must implement when they want to /// provide platform-specific in_app_purchase features. /// -/// Platform implementations should extend this class rather than implement it as `in_app_purchase` -/// does not consider newly added methods to be breaking changes. Extending this class -/// (using `extends`) ensures that the subclass will get the default implementation, while -/// platform implementations that `implements` this interface will be broken by newly added -/// [InAppPurchasePlatformAddition] methods. -abstract class InAppPurchasePlatformAddition extends PlatformInterface { - /// Constructs a InAppPurchasePlatform. - InAppPurchasePlatformAddition() : super(token: _token); - - static final Object _token = Object(); - - // Should only be accessed after setter is called. - static InAppPurchasePlatformAddition? _instance; - +/// Platforms that wants to introduce platform-specific public APIs should create +/// a class that either extend or implements [InAppPurchasePlatformAddition]. Then replace +/// the [InAppPurchasePlatformAddition.instance] with an instance of that class. +/// +/// We highly recommand against to have [InAppPurchasePlatformAddition] and [InAppPurchasePlatform] +/// being the same class. +abstract class InAppPurchasePlatformAddition { /// The instance containing the platform-specific in_app_purchase /// functionality. /// @@ -54,16 +47,5 @@ abstract class InAppPurchasePlatformAddition extends PlatformInterface { /// } /// } /// ``` - static InAppPurchasePlatformAddition? get instance => _instance; - - /// Platform-specific plugins should set this with their own platform-specific - /// class that extends [InAppPurchasePlatformAddition] when they register themselves. - static set instance(InAppPurchasePlatformAddition? instance) { - _instance = instance; - if (_instance == null) { - return; - } - PlatformInterface.verifyToken(instance!, _token); - assert(instance.runtimeType is! InAppPurchasePlatform); - } + static InAppPurchasePlatformAddition? instance; } diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart index 750599170990..d83b301d08ed 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart @@ -122,7 +122,6 @@ void main() { }); group('$InAppPurchasePlatformAddition', () { - setUp(() { InAppPurchasePlatformAddition.instance = null; }); @@ -131,11 +130,9 @@ void main() { expect(InAppPurchasePlatformAddition.instance, isNull); }); - test('Cannot be implemented with `implements`', () { - expect(() { - InAppPurchasePlatformAddition.instance = - ImplementsInAppPurchasePlatformAddition(); - }, throwsNoSuchMethodError); + test('Can be implemented.', () { + InAppPurchasePlatformAddition.instance = + ImplementsInAppPurchasePlatformAddition(); }); test('InAppPurchasePlatformAddition Can be extended', () { From 0f3d0b9728c1220370e3b50c70ac619fbd836dd3 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 3 May 2021 10:31:57 -0700 Subject: [PATCH 5/9] update docs --- .../lib/src/in_app_purchase_platform_addition.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart index 2d113ef4fc53..cbf38f2ff916 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart @@ -12,7 +12,9 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; /// a class that either extend or implements [InAppPurchasePlatformAddition]. Then replace /// the [InAppPurchasePlatformAddition.instance] with an instance of that class. /// -/// We highly recommand against to have [InAppPurchasePlatformAddition] and [InAppPurchasePlatform] +/// All the APIs added by [InAppPurchasePlatformAddition] implementers will be accessed from +/// [InAppPurchasePlatformAdditionProvider.getPlatformAddition] by the client APPs. +/// To avoid client APPs to directly call the [InAppPurchasePlatform] APIs, we highly recommand to not have [InAppPurchasePlatformAddition] and [InAppPurchasePlatform] /// being the same class. abstract class InAppPurchasePlatformAddition { /// The instance containing the platform-specific in_app_purchase From 899bafb0da6b33565fe6f1dac9a24f2c1840b793 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 3 May 2021 10:40:11 -0700 Subject: [PATCH 6/9] asert and test --- .../src/in_app_purchase_platform_addition.dart | 16 +++++++++++++--- .../test/in_app_purchase_platform_test.dart | 11 +++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart index cbf38f2ff916..1c1798a8d857 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart @@ -14,9 +14,11 @@ import 'package:plugin_platform_interface/plugin_platform_interface.dart'; /// /// All the APIs added by [InAppPurchasePlatformAddition] implementers will be accessed from /// [InAppPurchasePlatformAdditionProvider.getPlatformAddition] by the client APPs. -/// To avoid client APPs to directly call the [InAppPurchasePlatform] APIs, we highly recommand to not have [InAppPurchasePlatformAddition] and [InAppPurchasePlatform] -/// being the same class. +/// To avoid client APPs to directly call the [InAppPurchasePlatform] APIs, an [InAppPurchasePlatformAddition] implementation must not +/// be a type of [InAppPurchasePlatform]. abstract class InAppPurchasePlatformAddition { + static InAppPurchasePlatformAddition? _instance; + /// The instance containing the platform-specific in_app_purchase /// functionality. /// @@ -49,5 +51,13 @@ abstract class InAppPurchasePlatformAddition { /// } /// } /// ``` - static InAppPurchasePlatformAddition? instance; + static InAppPurchasePlatformAddition? get instance => _instance; + + /// Sets the instance to a desired [InAppPurchasePlatformAddition] implementation. + /// + /// The `instance` must not be a type of [InAppPurchasePlatform]. + static set instance(InAppPurchasePlatformAddition? instance) { + assert(!(instance is InAppPurchasePlatform)); + _instance = instance; + } } diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart index d83b301d08ed..f0c7f84d4a26 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart @@ -145,6 +145,13 @@ void main() { MockInAppPurchasePlatformAddition(); }); + test('Can not be a `InAppPurchasePlatform`', () { + expect( + () => InAppPurchasePlatformAddition.instance = + ExtendsInAppPurchasePlatformAdditionIsPlatformInterface(), + throwsAssertionError); + }); + test('Provider can provide', () { ImplementsInAppPurchasePlatformAdditionProvider.register(); final ImplementsInAppPurchasePlatformAdditionProvider provider = @@ -210,3 +217,7 @@ class ImplementsInAppPurchasePlatformAdditionProvider return InAppPurchasePlatformAddition.instance as T; } } + +class ExtendsInAppPurchasePlatformAdditionIsPlatformInterface + extends InAppPurchasePlatform + implements ExtendsInAppPurchasePlatformAddition {} From 8a7341dcb15bc1d0bb9f81fe65e927f553dc1a93 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Mon, 3 May 2021 10:40:54 -0700 Subject: [PATCH 7/9] tupo --- .../lib/src/in_app_purchase_platform_addition.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart index 1c1798a8d857..8c00f8a2fd68 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart @@ -53,7 +53,7 @@ abstract class InAppPurchasePlatformAddition { /// ``` static InAppPurchasePlatformAddition? get instance => _instance; - /// Sets the instance to a desired [InAppPurchasePlatformAddition] implementation. + /// Set the instance to a desired [InAppPurchasePlatformAddition] implementation. /// /// The `instance` must not be a type of [InAppPurchasePlatform]. static set instance(InAppPurchasePlatformAddition? instance) { From a697f099a8c4d009778f118cff7f066b65c9b281 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Tue, 4 May 2021 14:22:34 -0700 Subject: [PATCH 8/9] fix analyzer errors --- .../lib/src/in_app_purchase_platform_addition.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart index 8c00f8a2fd68..5d9dac210e93 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart @@ -3,8 +3,8 @@ // found in the LICENSE file. import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart'; -import 'package:plugin_platform_interface/plugin_platform_interface.dart'; +// ignore: avoid_classes_with_only_static_members /// The interface that platform implementations must implement when they want to /// provide platform-specific in_app_purchase features. /// @@ -57,7 +57,7 @@ abstract class InAppPurchasePlatformAddition { /// /// The `instance` must not be a type of [InAppPurchasePlatform]. static set instance(InAppPurchasePlatformAddition? instance) { - assert(!(instance is InAppPurchasePlatform)); + assert(instance is! InAppPurchasePlatform); _instance = instance; } } From b8774b6a2eeba82851c8bd02e5d062276b75bad7 Mon Sep 17 00:00:00 2001 From: Chris Yang Date: Wed, 5 May 2021 11:18:22 -0700 Subject: [PATCH 9/9] review --- .../lib/src/in_app_purchase_platform_addition.dart | 14 +++++++------- .../lib/src/types/product_details_response.dart | 2 +- .../test/in_app_purchase_platform_test.dart | 12 ------------ 3 files changed, 8 insertions(+), 20 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart index 5d9dac210e93..746675549295 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/in_app_purchase_platform_addition.dart @@ -9,13 +9,13 @@ import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_inte /// provide platform-specific in_app_purchase features. /// /// Platforms that wants to introduce platform-specific public APIs should create -/// a class that either extend or implements [InAppPurchasePlatformAddition]. Then replace -/// the [InAppPurchasePlatformAddition.instance] with an instance of that class. +/// a class that either extend or implements [InAppPurchasePlatformAddition]. Then set +/// the [InAppPurchasePlatformAddition.instance] to an instance of that class. /// -/// All the APIs added by [InAppPurchasePlatformAddition] implementers will be accessed from +/// All the APIs added by [InAppPurchasePlatformAddition] implementations will be accessed from /// [InAppPurchasePlatformAdditionProvider.getPlatformAddition] by the client APPs. -/// To avoid client APPs to directly call the [InAppPurchasePlatform] APIs, an [InAppPurchasePlatformAddition] implementation must not -/// be a type of [InAppPurchasePlatform]. +/// To avoid clients directly calling [InAppPurchasePlatform] APIs, +/// an [InAppPurchasePlatformAddition] implementation should not be a type of [InAppPurchasePlatform]. abstract class InAppPurchasePlatformAddition { static InAppPurchasePlatformAddition? _instance; @@ -53,9 +53,9 @@ abstract class InAppPurchasePlatformAddition { /// ``` static InAppPurchasePlatformAddition? get instance => _instance; - /// Set the instance to a desired [InAppPurchasePlatformAddition] implementation. + /// Sets the instance to a desired [InAppPurchasePlatformAddition] implementation. /// - /// The `instance` must not be a type of [InAppPurchasePlatform]. + /// The `instance` should not be a type of [InAppPurchasePlatform]. static set instance(InAppPurchasePlatformAddition? instance) { assert(instance is! InAppPurchasePlatform); _instance = instance; diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart index d8331d6560d8..11b244a84ae3 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/lib/src/types/product_details_response.dart @@ -18,7 +18,7 @@ class ProductDetailsResponse { /// The list of identifiers that are in the `identifiers` of [InAppPurchasePlatform.queryProductDetails] but failed to be fetched. /// - /// There's multiple platform-specific reasons that product information could fail to be fetched, + /// There are multiple platform-specific reasons that product information could fail to be fetched, /// ranging from products not being correctly configured in the storefront to the queried IDs not existing. final List notFoundIDs; diff --git a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart index f0c7f84d4a26..9c0f2dc00020 100644 --- a/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_platform_interface/test/in_app_purchase_platform_test.dart @@ -140,11 +140,6 @@ void main() { ExtendsInAppPurchasePlatformAddition(); }); - test('Can be mocked with `implements`', () { - InAppPurchasePlatformAddition.instance = - MockInAppPurchasePlatformAddition(); - }); - test('Can not be a `InAppPurchasePlatform`', () { expect( () => InAppPurchasePlatformAddition.instance = @@ -195,13 +190,6 @@ class ImplementsInAppPurchasePlatformAddition dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation); } -class MockInAppPurchasePlatformAddition extends Mock - with - // ignore: prefer_mixin - MockPlatformInterfaceMixin - implements - InAppPurchasePlatformAddition {} - class ExtendsInAppPurchasePlatformAddition extends InAppPurchasePlatformAddition {}