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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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;
}
}