Skip to content

Commit 83959fb

Browse files
authored
[in_app_purchases] Fix mismatching method signature strings (#4040)
In the upgrade to billing client v5 in #3752, some method signature strings on the Java side were updated. Unfortunately, as the Dart side was not updated. This mismatch broke the interaction between the Dart and native Android code through the method channels. This PR updates the strings on the Dart side so the method invocation work correctly again. This is a follow-up to - flutter/flutter#110909 - flutter/flutter#107370 - flutter/flutter#114265
1 parent 7d64098 commit 83959fb

File tree

7 files changed

+152
-35
lines changed

7 files changed

+152
-35
lines changed

packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.3.0+1
2+
3+
* Fixes misaligned method signature strings.
4+
15
## 0.3.0
26
* **BREAKING CHANGE**: Removes `launchPriceChangeConfirmationFlow` from `InAppPurchaseAndroidPlatform`. Price changes are now [handled by Google Play](https://developer.android.com/google/play/billing/subscriptions#price-change).
37
* Returns both base plans and offers when `queryProductDetailsAsync` is called.

packages/in_app_purchase/in_app_purchase_android/example/integration_test/in_app_purchase_test.dart

Lines changed: 108 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,126 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'package:flutter/services.dart';
56
import 'package:flutter_test/flutter_test.dart';
7+
import 'package:in_app_purchase_android/billing_client_wrappers.dart';
68
import 'package:in_app_purchase_android/in_app_purchase_android.dart';
79
import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_interface.dart';
810
import 'package:integration_test/integration_test.dart';
911

1012
void main() {
1113
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
1214

15+
setUp(() {
16+
InAppPurchaseAndroidPlatform.registerPlatform();
17+
});
18+
1319
testWidgets('Can create InAppPurchaseAndroid instance',
1420
(WidgetTester tester) async {
15-
InAppPurchaseAndroidPlatform.registerPlatform();
1621
final InAppPurchasePlatform androidPlatform =
1722
InAppPurchasePlatform.instance;
1823
expect(androidPlatform, isNotNull);
1924
});
25+
26+
group('Method channel interaction works for', () {
27+
late final BillingClient billingClient;
28+
29+
setUpAll(() {
30+
billingClient = BillingClient((PurchasesResultWrapper _) {});
31+
});
32+
33+
test('BillingClient.acknowledgePurchase', () async {
34+
try {
35+
await billingClient.acknowledgePurchase('purchaseToken');
36+
} on MissingPluginException {
37+
fail('Method channel is not setup correctly');
38+
}
39+
});
40+
41+
test('BillingClient.consumeAsync', () async {
42+
try {
43+
await billingClient.consumeAsync('purchaseToken');
44+
} on MissingPluginException {
45+
fail('Method channel is not setup correctly');
46+
}
47+
});
48+
49+
test('BillingClient.endConnection', () async {
50+
try {
51+
await billingClient.endConnection();
52+
} on MissingPluginException {
53+
fail('Method channel is not setup correctly');
54+
}
55+
});
56+
57+
test('BillingClient.isFeatureSupported', () async {
58+
try {
59+
await billingClient
60+
.isFeatureSupported(BillingClientFeature.productDetails);
61+
} on MissingPluginException {
62+
fail('Method channel is not setup correctly');
63+
}
64+
});
65+
66+
test('BillingClient.isReady', () async {
67+
try {
68+
await billingClient.isReady();
69+
} on MissingPluginException {
70+
fail('Method channel is not setup correctly');
71+
}
72+
});
73+
74+
test('BillingClient.launchBillingFlow', () async {
75+
try {
76+
await billingClient.launchBillingFlow(product: 'product');
77+
} on MissingPluginException {
78+
fail('Method channel is not setup correctly');
79+
} on PlatformException catch (e) {
80+
// A [PlatformException] is expected, as we do not fetch products first.
81+
if (e.code != 'NOT_FOUND') {
82+
rethrow;
83+
}
84+
}
85+
});
86+
87+
test('BillingClient.queryProductDetails', () async {
88+
try {
89+
await billingClient
90+
.queryProductDetails(productList: <ProductWrapper>[]);
91+
} on MissingPluginException {
92+
fail('Method channel is not setup correctly');
93+
} on PlatformException catch (e) {
94+
// A [PlatformException] is expected, as we send an empty product list.
95+
if (!(e.message?.startsWith('Product list cannot be empty.') ??
96+
false)) {
97+
rethrow;
98+
}
99+
}
100+
});
101+
102+
test('BillingClient.queryPurchaseHistory', () async {
103+
try {
104+
await billingClient.queryPurchaseHistory(ProductType.inapp);
105+
} on MissingPluginException {
106+
fail('Method channel is not setup correctly');
107+
}
108+
});
109+
110+
test('BillingClient.queryPurchases', () async {
111+
try {
112+
await billingClient.queryPurchases(ProductType.inapp);
113+
} on MissingPluginException {
114+
fail('Method channel is not setup correctly');
115+
}
116+
});
117+
118+
test('BillingClient.startConnection', () async {
119+
try {
120+
await billingClient.startConnection(
121+
onBillingServiceDisconnected: () {});
122+
} on MissingPluginException {
123+
fail('Method channel is not setup correctly');
124+
}
125+
});
126+
});
20127
}

packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.dart

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ part 'billing_client_wrapper.g.dart';
1616
/// Method identifier for the OnPurchaseUpdated method channel method.
1717
@visibleForTesting
1818
const String kOnPurchasesUpdated =
19-
'PurchasesUpdatedListener#onPurchasesUpdated(int, List<Purchase>)';
19+
'PurchasesUpdatedListener#onPurchasesUpdated(BillingResult, List<Purchase>)';
2020
const String _kOnBillingServiceDisconnected =
2121
'BillingClientStateListener#onBillingServiceDisconnected()';
2222

@@ -234,16 +234,18 @@ class BillingClient {
234234
/// server if at all possible. See ["Verify a
235235
/// purchase"](https://developer.android.com/google/play/billing/billing_library_overview#Verify).
236236
///
237-
/// This wraps [`BillingClient#queryPurchases(String
238-
/// productType)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#queryPurchasesAsync(com.android.billingclient.api.QueryPurchasesParams,%20com.android.billingclient.api.PurchasesResponseListener)).
237+
/// This wraps
238+
/// [`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)).
239239
Future<PurchasesResultWrapper> queryPurchases(ProductType productType) async {
240240
assert(productType != null);
241-
return PurchasesResultWrapper.fromJson((await channel
242-
.invokeMapMethod<String, dynamic>(
243-
'BillingClient#queryPurchases(String)', <String, dynamic>{
244-
'productType': const ProductTypeConverter().toJson(productType)
245-
})) ??
246-
<String, dynamic>{});
241+
return PurchasesResultWrapper.fromJson(
242+
(await channel.invokeMapMethod<String, dynamic>(
243+
'BillingClient#queryPurchasesAsync(QueryPurchaseParams, PurchaseResponseListener)',
244+
<String, dynamic>{
245+
'productType': const ProductTypeConverter().toJson(productType)
246+
},
247+
)) ??
248+
<String, dynamic>{});
247249
}
248250

249251
/// Fetches purchase history for the given [ProductType].
@@ -256,16 +258,15 @@ class BillingClient {
256258
/// server if at all possible. See ["Verify a
257259
/// purchase"](https://developer.android.com/google/play/billing/billing_library_overview#Verify).
258260
///
259-
/// This wraps [`BillingClient#queryPurchaseHistoryAsync(String productType,
260-
/// PurchaseHistoryResponseListener
261-
/// listener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient#queryPurchaseHistoryAsync(com.android.billingclient.api.QueryPurchaseHistoryParams,%20com.android.billingclient.api.PurchaseHistoryResponseListener)).
261+
/// This wraps
262+
/// [`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)).
262263
Future<PurchasesHistoryResult> queryPurchaseHistory(
263264
ProductType productType) async {
264265
assert(productType != null);
265-
return PurchasesHistoryResult.fromJson((await channel
266-
.invokeMapMethod<String, dynamic>(
267-
'BillingClient#queryPurchaseHistoryAsync(String)',
268-
<String, dynamic>{
266+
return PurchasesHistoryResult.fromJson((await channel.invokeMapMethod<
267+
String, dynamic>(
268+
'BillingClient#queryPurchaseHistoryAsync(QueryPurchaseHistoryParams, PurchaseHistoryResponseListener)',
269+
<String, dynamic>{
269270
'productType': const ProductTypeConverter().toJson(productType)
270271
})) ??
271272
<String, dynamic>{});
@@ -276,13 +277,14 @@ class BillingClient {
276277
/// Consuming can only be done on an item that's owned, and as a result of consumption, the user will no longer own it.
277278
/// Consumption is done asynchronously. The method returns a Future containing a [BillingResultWrapper].
278279
///
279-
/// 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))
280+
/// This wraps
281+
/// [`BillingClient#consumeAsync(ConsumeParams, ConsumeResponseListener)`](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.html#consumeAsync(java.lang.String,%20com.android.billingclient.api.ConsumeResponseListener))
280282
Future<BillingResultWrapper> consumeAsync(String purchaseToken) async {
281283
assert(purchaseToken != null);
282-
return BillingResultWrapper.fromJson((await channel
283-
.invokeMapMethod<String, dynamic>(
284-
'BillingClient#consumeAsync(String, ConsumeResponseListener)',
285-
<String, dynamic>{
284+
return BillingResultWrapper.fromJson((await channel.invokeMapMethod<String,
285+
dynamic>(
286+
'BillingClient#consumeAsync(ConsumeParams, ConsumeResponseListener)',
287+
<String, dynamic>{
286288
'purchaseToken': purchaseToken,
287289
})) ??
288290
<String, dynamic>{});
@@ -304,12 +306,13 @@ class BillingClient {
304306
/// Please refer to [acknowledge](https://developer.android.com/google/play/billing/billing_library_overview#acknowledge) for more
305307
/// details.
306308
///
307-
/// 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))
309+
/// This wraps
310+
/// [`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))
308311
Future<BillingResultWrapper> acknowledgePurchase(String purchaseToken) async {
309312
assert(purchaseToken != null);
310313
return BillingResultWrapper.fromJson((await channel.invokeMapMethod<String,
311314
dynamic>(
312-
'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)',
315+
'BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)',
313316
<String, dynamic>{
314317
'purchaseToken': purchaseToken,
315318
})) ??

packages/in_app_purchase/in_app_purchase_android/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: in_app_purchase_android
22
description: An implementation for the Android platform of the Flutter `in_app_purchase` plugin. This uses the Android BillingClient APIs.
33
repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_android
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
5-
version: 0.3.0
5+
version: 0.3.0+1
66

77
environment:
88
sdk: ">=2.18.0 <4.0.0"

packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/billing_client_wrapper_test.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,7 @@ void main() {
401401

402402
group('queryPurchases', () {
403403
const String queryPurchasesMethodName =
404-
'BillingClient#queryPurchases(String)';
404+
'BillingClient#queryPurchasesAsync(QueryPurchaseParams, PurchaseResponseListener)';
405405

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

468468
group('queryPurchaseHistory', () {
469469
const String queryPurchaseHistoryMethodName =
470-
'BillingClient#queryPurchaseHistoryAsync(String)';
470+
'BillingClient#queryPurchaseHistoryAsync(QueryPurchaseHistoryParams, PurchaseHistoryResponseListener)';
471471

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

532532
group('consume purchases', () {
533533
const String consumeMethodName =
534-
'BillingClient#consumeAsync(String, ConsumeResponseListener)';
534+
'BillingClient#consumeAsync(ConsumeParams, ConsumeResponseListener)';
535535
test('consume purchase async success', () async {
536536
const BillingResponse expectedCode = BillingResponse.ok;
537537
const String debugMessage = 'dummy message';
@@ -564,7 +564,7 @@ void main() {
564564

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

580580
expect(billingResult, equals(expectedBillingResult));
581581
});
582+
582583
test('handles method channel returning null', () async {
583584
stubPlatform.addResponse(
584585
name: acknowledgeMethodName,

packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_addition_test.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void main() {
4444

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

6565
group('queryPastPurchase', () {
6666
group('queryPurchaseDetails', () {
67-
const String queryMethodName = 'BillingClient#queryPurchases(String)';
67+
const String queryMethodName =
68+
'BillingClient#queryPurchasesAsync(QueryPurchaseParams, PurchaseResponseListener)';
6869
test('handles error', () async {
6970
const String debugMessage = 'dummy message';
7071
const BillingResponse responseCode = BillingResponse.developerError;

packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ void main() {
2525
'BillingClient#startConnection(BillingClientStateListener)';
2626
const String endConnectionCall = 'BillingClient#endConnection()';
2727
const String acknowledgePurchaseCall =
28-
'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
28+
'BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
2929
const String onBillingServiceDisconnectedCallback =
3030
'BillingClientStateListener#onBillingServiceDisconnected()';
3131

@@ -213,7 +213,8 @@ void main() {
213213
});
214214

215215
group('restorePurchases', () {
216-
const String queryMethodName = 'BillingClient#queryPurchases(String)';
216+
const String queryMethodName =
217+
'BillingClient#queryPurchasesAsync(QueryPurchaseParams, PurchaseResponseListener)';
217218
test('handles error', () async {
218219
const String debugMessage = 'dummy message';
219220
const BillingResponse responseCode = BillingResponse.developerError;
@@ -331,7 +332,7 @@ void main() {
331332
const String launchMethodName =
332333
'BillingClient#launchBillingFlow(Activity, BillingFlowParams)';
333334
const String consumeMethodName =
334-
'BillingClient#consumeAsync(String, ConsumeResponseListener)';
335+
'BillingClient#consumeAsync(ConsumeParams, ConsumeResponseListener)';
335336

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

826827
group('complete purchase', () {
827828
const String completeMethodName =
828-
'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
829+
'BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)';
829830
test('complete purchase success', () async {
830831
const BillingResponse expectedCode = BillingResponse.ok;
831832
const String debugMessage = 'dummy message';

0 commit comments

Comments
 (0)