Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/in_app_purchase/in_app_purchase/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<String> notFoundIDs;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,28 @@ abstract class InAppPurchasePlatform extends PlatformInterface {

/// The instance of [InAppPurchasePlatform] to use.
///
/// Defaults to `null`.
static InAppPurchasePlatform? get instance => _instance;

static InAppPurchasePlatform? _instance;
/// Must be set before accessing.
static InAppPurchasePlatform get instance => _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;
}

// 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,29 @@
// 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.
/// 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/replace ... with/set ... to/ (by default there's no instance, so there's nothing to replace)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/// 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.
///
/// Returns `null` by default.
///
/// To implement additional functionality extend
/// [`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
Expand All @@ -22,7 +33,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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 extends InAppPurchasePlatformAddition>();
T getPlatformAddition<T extends InAppPurchasePlatformAddition?>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/There's/There are/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

/// ranging from products not being correctly configured in the storefront to the queried IDs not existing.
final List<String> notFoundIDs;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,18 @@ 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(
Expand Down Expand Up @@ -124,6 +120,48 @@ void main() {
);
});
});

group('$InAppPurchasePlatformAddition', () {
setUp(() {
InAppPurchasePlatformAddition.instance = null;
});

test('Cannot be implemented with `implements`', () {
expect(InAppPurchasePlatformAddition.instance, isNull);
});

test('Can be implemented.', () {
InAppPurchasePlatformAddition.instance =
ImplementsInAppPurchasePlatformAddition();
});

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);
});

test('Provider can provide `null`', () {
final ImplementsInAppPurchasePlatformAdditionProvider provider =
ImplementsInAppPurchasePlatformAdditionProvider();
final InAppPurchasePlatformAddition? addition =
provider.getPlatformAddition();
expect(addition, isNull);
});
});
}

class ImplementsInAppPurchasePlatform implements InAppPurchasePlatform {
Expand All @@ -143,3 +181,32 @@ 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This shouldn't still be needed, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

implements
InAppPurchasePlatformAddition {}

class ExtendsInAppPurchasePlatformAddition
extends InAppPurchasePlatformAddition {}

class ImplementsInAppPurchasePlatformAdditionProvider
implements InAppPurchasePlatformAdditionProvider {
static void register() {
InAppPurchasePlatformAddition.instance =
ExtendsInAppPurchasePlatformAddition();
}

@override
T getPlatformAddition<T extends InAppPurchasePlatformAddition?>() {
return InAppPurchasePlatformAddition.instance as T;
}
}