Skip to content

[in_app_purchases] Fix mismatching method signature strings #4040

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 22, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.3.0+1

* Fixes misaligned method signature strings.

## 0.3.0
* **BREAKING CHANGE**: Removes `launchPriceChangeConfirmationFlow` from `InAppPurchaseAndroidPlatform`. Price changes are now [handled by Google Play](https://developer.android.com/google/play/billing/subscriptions#price-change).
* Returns both base plans and offers when `queryProductDetailsAsync` is called.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,126 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:in_app_purchase_android/billing_client_wrappers.dart';
import 'package:in_app_purchase_android/in_app_purchase_android.dart';
import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
import 'package:integration_test/integration_test.dart';

void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();

setUp(() {
InAppPurchaseAndroidPlatform.registerPlatform();
});

testWidgets('Can create InAppPurchaseAndroid instance',
(WidgetTester tester) async {
InAppPurchaseAndroidPlatform.registerPlatform();
final InAppPurchasePlatform androidPlatform =
InAppPurchasePlatform.instance;
expect(androidPlatform, isNotNull);
});

group('Method channel interaction works for', () {
late final BillingClient billingClient;

setUpAll(() {
billingClient = BillingClient((PurchasesResultWrapper _) {});
});

test('BillingClient.acknowledgePurchase', () async {
try {
await billingClient.acknowledgePurchase('purchaseToken');
} on MissingPluginException {
fail('Method channel is not setup correctly');
}
});

test('BillingClient.consumeAsync', () async {
try {
await billingClient.consumeAsync('purchaseToken');
} on MissingPluginException {
fail('Method channel is not setup correctly');
}
});

test('BillingClient.endConnection', () async {
try {
await billingClient.endConnection();
} on MissingPluginException {
fail('Method channel is not setup correctly');
}
});

test('BillingClient.isFeatureSupported', () async {
try {
await billingClient
.isFeatureSupported(BillingClientFeature.productDetails);
} on MissingPluginException {
fail('Method channel is not setup correctly');
}
});

test('BillingClient.isReady', () async {
try {
await billingClient.isReady();
} on MissingPluginException {
fail('Method channel is not setup correctly');
}
});

test('BillingClient.launchBillingFlow', () async {
try {
await billingClient.launchBillingFlow(product: 'product');
} on MissingPluginException {
fail('Method channel is not setup correctly');
} on PlatformException catch (e) {
// A [PlatformException] is expected, as we do not fetch products first.
if (e.code != 'NOT_FOUND') {
rethrow;
}
}
});

test('BillingClient.queryProductDetails', () async {
try {
await billingClient
.queryProductDetails(productList: <ProductWrapper>[]);
} on MissingPluginException {
fail('Method channel is not setup correctly');
} on PlatformException catch (e) {
// A [PlatformException] is expected, as we send an empty product list.
if (!(e.message?.startsWith('Product list cannot be empty.') ??
false)) {
rethrow;
}
}
});

test('BillingClient.queryPurchaseHistory', () async {
try {
await billingClient.queryPurchaseHistory(ProductType.inapp);
} on MissingPluginException {
fail('Method channel is not setup correctly');
}
});

test('BillingClient.queryPurchases', () async {
try {
await billingClient.queryPurchases(ProductType.inapp);
} on MissingPluginException {
fail('Method channel is not setup correctly');
}
});

test('BillingClient.startConnection', () async {
try {
await billingClient.startConnection(
onBillingServiceDisconnected: () {});
} on MissingPluginException {
fail('Method channel is not setup correctly');
}
});
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ part 'billing_client_wrapper.g.dart';
/// Method identifier for the OnPurchaseUpdated method channel method.
@visibleForTesting
const String kOnPurchasesUpdated =
'PurchasesUpdatedListener#onPurchasesUpdated(int, List<Purchase>)';
'PurchasesUpdatedListener#onPurchasesUpdated(BillingResult, List<Purchase>)';
const String _kOnBillingServiceDisconnected =
'BillingClientStateListener#onBillingServiceDisconnected()';

Expand Down Expand Up @@ -234,16 +234,18 @@ class BillingClient {
/// server if at all possible. See ["Verify a
/// purchase"](https://developer.android.com/google/play/billing/billing_library_overview#Verify).
///
/// This wraps [`BillingClient#queryPurchases(String
/// productType)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#queryPurchasesAsync(com.android.billingclient.api.QueryPurchasesParams,%20com.android.billingclient.api.PurchasesResponseListener)).
/// This wraps
/// [`BillingClient#queryPurchasesAsync(QueryPurchaseParams, PurchaseResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#queryPurchasesAsync(com.android.billingclient.api.QueryPurchasesParams,%20com.android.billingclient.api.PurchasesResponseListener)).
Future<PurchasesResultWrapper> queryPurchases(ProductType productType) async {
assert(productType != null);
return PurchasesResultWrapper.fromJson((await channel
.invokeMapMethod<String, dynamic>(
'BillingClient#queryPurchases(String)', <String, dynamic>{
'productType': const ProductTypeConverter().toJson(productType)
})) ??
<String, dynamic>{});
return PurchasesResultWrapper.fromJson(
(await channel.invokeMapMethod<String, dynamic>(
'BillingClient#queryPurchasesAsync(QueryPurchaseParams, PurchaseResponseListener)',
<String, dynamic>{
'productType': const ProductTypeConverter().toJson(productType)
},
)) ??
<String, dynamic>{});
}

/// Fetches purchase history for the given [ProductType].
Expand All @@ -256,16 +258,15 @@ class BillingClient {
/// server if at all possible. See ["Verify a
/// purchase"](https://developer.android.com/google/play/billing/billing_library_overview#Verify).
///
/// This wraps [`BillingClient#queryPurchaseHistoryAsync(String productType,
/// PurchaseHistoryResponseListener
/// listener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#queryPurchaseHistoryAsync(com.android.billingclient.api.QueryPurchaseHistoryParams,%20com.android.billingclient.api.PurchaseHistoryResponseListener)).
/// This wraps
/// [`BillingClient#queryPurchaseHistoryAsync(QueryPurchaseHistoryParams, PurchaseHistoryResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#queryPurchaseHistoryAsync(com.android.billingclient.api.QueryPurchaseHistoryParams,%20com.android.billingclient.api.PurchaseHistoryResponseListener)).
Future<PurchasesHistoryResult> queryPurchaseHistory(
ProductType productType) async {
assert(productType != null);
return PurchasesHistoryResult.fromJson((await channel
.invokeMapMethod<String, dynamic>(
'BillingClient#queryPurchaseHistoryAsync(String)',
<String, dynamic>{
return PurchasesHistoryResult.fromJson((await channel.invokeMapMethod<
String, dynamic>(
'BillingClient#queryPurchaseHistoryAsync(QueryPurchaseHistoryParams, PurchaseHistoryResponseListener)',
<String, dynamic>{
'productType': const ProductTypeConverter().toJson(productType)
})) ??
<String, dynamic>{});
Expand All @@ -276,13 +277,14 @@ class BillingClient {
/// Consuming can only be done on an item that's owned, and as a result of consumption, the user will no longer own it.
/// Consumption is done asynchronously. The method returns a Future containing a [BillingResultWrapper].
///
/// This wraps [`BillingClient#consumeAsync(String, ConsumeResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#consumeAsync(java.lang.String,%20com.android.billingclient.api.ConsumeResponseListener))
/// This wraps
/// [`BillingClient#consumeAsync(ConsumeParams, ConsumeResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#consumeAsync(java.lang.String,%20com.android.billingclient.api.ConsumeResponseListener))
Future<BillingResultWrapper> consumeAsync(String purchaseToken) async {
assert(purchaseToken != null);
return BillingResultWrapper.fromJson((await channel
.invokeMapMethod<String, dynamic>(
'BillingClient#consumeAsync(String, ConsumeResponseListener)',
<String, dynamic>{
return BillingResultWrapper.fromJson((await channel.invokeMapMethod<String,
dynamic>(
'BillingClient#consumeAsync(ConsumeParams, ConsumeResponseListener)',
<String, dynamic>{
'purchaseToken': purchaseToken,
})) ??
<String, dynamic>{});
Expand All @@ -304,12 +306,13 @@ class BillingClient {
/// Please refer to [acknowledge](https://developer.android.com/google/play/billing/billing_library_overview#acknowledge) for more
/// details.
///
/// This wraps [`BillingClient#acknowledgePurchase(String, AcknowledgePurchaseResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#acknowledgePurchase(com.android.billingclient.api.AcknowledgePurchaseParams,%20com.android.billingclient.api.AcknowledgePurchaseResponseListener))
/// This wraps
/// [`BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#acknowledgePurchase(com.android.billingclient.api.AcknowledgePurchaseParams,%20com.android.billingclient.api.AcknowledgePurchaseResponseListener))
Future<BillingResultWrapper> acknowledgePurchase(String purchaseToken) async {
assert(purchaseToken != null);
return BillingResultWrapper.fromJson((await channel.invokeMapMethod<String,
dynamic>(
'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)',
'BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)',
<String, dynamic>{
'purchaseToken': purchaseToken,
})) ??
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: in_app_purchase_android
description: An implementation for the Android platform of the Flutter `in_app_purchase` plugin. This uses the Android BillingClient APIs.
repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_android
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
version: 0.3.0
version: 0.3.0+1

environment:
sdk: ">=2.18.0 <4.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ void main() {

group('queryPurchases', () {
const String queryPurchasesMethodName =
'BillingClient#queryPurchases(String)';
'BillingClient#queryPurchasesAsync(QueryPurchaseParams, PurchaseResponseListener)';

test('serializes and deserializes data', () async {
const BillingResponse expectedCode = BillingResponse.ok;
Expand Down Expand Up @@ -467,7 +467,7 @@ void main() {

group('queryPurchaseHistory', () {
const String queryPurchaseHistoryMethodName =
'BillingClient#queryPurchaseHistoryAsync(String)';
'BillingClient#queryPurchaseHistoryAsync(QueryPurchaseHistoryParams, PurchaseHistoryResponseListener)';

test('serializes and deserializes data', () async {
const BillingResponse expectedCode = BillingResponse.ok;
Expand Down Expand Up @@ -531,7 +531,7 @@ void main() {

group('consume purchases', () {
const String consumeMethodName =
'BillingClient#consumeAsync(String, ConsumeResponseListener)';
'BillingClient#consumeAsync(ConsumeParams, ConsumeResponseListener)';
test('consume purchase async success', () async {
const BillingResponse expectedCode = BillingResponse.ok;
const String debugMessage = 'dummy message';
Expand Down Expand Up @@ -564,7 +564,7 @@ void main() {

group('acknowledge purchases', () {
const String acknowledgeMethodName =
'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
'BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
test('acknowledge purchase success', () async {
const BillingResponse expectedCode = BillingResponse.ok;
const String debugMessage = 'dummy message';
Expand All @@ -579,6 +579,7 @@ void main() {

expect(billingResult, equals(expectedBillingResult));
});

test('handles method channel returning null', () async {
stubPlatform.addResponse(
name: acknowledgeMethodName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ void main() {

group('consume purchases', () {
const String consumeMethodName =
'BillingClient#consumeAsync(String, ConsumeResponseListener)';
'BillingClient#consumeAsync(ConsumeParams, ConsumeResponseListener)';
test('consume purchase async success', () async {
const BillingResponse expectedCode = BillingResponse.ok;
const String debugMessage = 'dummy message';
Expand All @@ -64,7 +64,8 @@ void main() {

group('queryPastPurchase', () {
group('queryPurchaseDetails', () {
const String queryMethodName = 'BillingClient#queryPurchases(String)';
const String queryMethodName =
'BillingClient#queryPurchasesAsync(QueryPurchaseParams, PurchaseResponseListener)';
test('handles error', () async {
const String debugMessage = 'dummy message';
const BillingResponse responseCode = BillingResponse.developerError;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ void main() {
'BillingClient#startConnection(BillingClientStateListener)';
const String endConnectionCall = 'BillingClient#endConnection()';
const String acknowledgePurchaseCall =
'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
'BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
const String onBillingServiceDisconnectedCallback =
'BillingClientStateListener#onBillingServiceDisconnected()';

Expand Down Expand Up @@ -213,7 +213,8 @@ void main() {
});

group('restorePurchases', () {
const String queryMethodName = 'BillingClient#queryPurchases(String)';
const String queryMethodName =
'BillingClient#queryPurchasesAsync(QueryPurchaseParams, PurchaseResponseListener)';
test('handles error', () async {
const String debugMessage = 'dummy message';
const BillingResponse responseCode = BillingResponse.developerError;
Expand Down Expand Up @@ -331,7 +332,7 @@ void main() {
const String launchMethodName =
'BillingClient#launchBillingFlow(Activity, BillingFlowParams)';
const String consumeMethodName =
'BillingClient#consumeAsync(String, ConsumeResponseListener)';
'BillingClient#consumeAsync(ConsumeParams, ConsumeResponseListener)';

test('buy non consumable, serializes and deserializes data', () async {
const ProductDetailsWrapper productDetails = dummyOneTimeProductDetails;
Expand Down Expand Up @@ -825,7 +826,7 @@ void main() {

group('complete purchase', () {
const String completeMethodName =
'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
'BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
test('complete purchase success', () async {
const BillingResponse expectedCode = BillingResponse.ok;
const String debugMessage = 'dummy message';
Expand Down