diff --git a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md index bf08b2db0ae81..053daa4478dd9 100644 --- a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md @@ -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. diff --git a/packages/in_app_purchase/in_app_purchase_android/example/integration_test/in_app_purchase_test.dart b/packages/in_app_purchase/in_app_purchase_android/example/integration_test/in_app_purchase_test.dart index bb0e1675090db..ecf43d290c5fa 100644 --- a/packages/in_app_purchase/in_app_purchase_android/example/integration_test/in_app_purchase_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/example/integration_test/in_app_purchase_test.dart @@ -2,7 +2,9 @@ // 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'; @@ -10,11 +12,116 @@ 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: []); + } 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'); + } + }); + }); } diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.dart index cf8e0f7723627..564b7b4b3686a 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.dart @@ -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)'; + 'PurchasesUpdatedListener#onPurchasesUpdated(BillingResult, List)'; const String _kOnBillingServiceDisconnected = 'BillingClientStateListener#onBillingServiceDisconnected()'; @@ -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 queryPurchases(ProductType productType) async { assert(productType != null); - return PurchasesResultWrapper.fromJson((await channel - .invokeMapMethod( - 'BillingClient#queryPurchases(String)', { - 'productType': const ProductTypeConverter().toJson(productType) - })) ?? - {}); + return PurchasesResultWrapper.fromJson( + (await channel.invokeMapMethod( + 'BillingClient#queryPurchasesAsync(QueryPurchaseParams, PurchaseResponseListener)', + { + 'productType': const ProductTypeConverter().toJson(productType) + }, + )) ?? + {}); } /// Fetches purchase history for the given [ProductType]. @@ -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 queryPurchaseHistory( ProductType productType) async { assert(productType != null); - return PurchasesHistoryResult.fromJson((await channel - .invokeMapMethod( - 'BillingClient#queryPurchaseHistoryAsync(String)', - { + return PurchasesHistoryResult.fromJson((await channel.invokeMapMethod< + String, dynamic>( + 'BillingClient#queryPurchaseHistoryAsync(QueryPurchaseHistoryParams, PurchaseHistoryResponseListener)', + { 'productType': const ProductTypeConverter().toJson(productType) })) ?? {}); @@ -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 consumeAsync(String purchaseToken) async { assert(purchaseToken != null); - return BillingResultWrapper.fromJson((await channel - .invokeMapMethod( - 'BillingClient#consumeAsync(String, ConsumeResponseListener)', - { + return BillingResultWrapper.fromJson((await channel.invokeMapMethod( + 'BillingClient#consumeAsync(ConsumeParams, ConsumeResponseListener)', + { 'purchaseToken': purchaseToken, })) ?? {}); @@ -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 acknowledgePurchase(String purchaseToken) async { assert(purchaseToken != null); return BillingResultWrapper.fromJson((await channel.invokeMapMethod( - 'BillingClient#(AcknowledgePurchaseParams params, (AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)', + 'BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)', { 'purchaseToken': purchaseToken, })) ?? diff --git a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml index 08e5f4d31192d..3bf2e84fe870b 100644 --- a/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml +++ b/packages/in_app_purchase/in_app_purchase_android/pubspec.yaml @@ -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" diff --git a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/billing_client_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/billing_client_wrapper_test.dart index 0c21a17ef58c0..ad5a7112f4dd8 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/billing_client_wrapper_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/billing_client_wrapper_test.dart @@ -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; @@ -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; @@ -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'; @@ -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'; @@ -579,6 +579,7 @@ void main() { expect(billingResult, equals(expectedBillingResult)); }); + test('handles method channel returning null', () async { stubPlatform.addResponse( name: acknowledgeMethodName, diff --git a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_addition_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_addition_test.dart index b56cb9b5f40a9..cae9396431a50 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_addition_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_addition_test.dart @@ -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'; @@ -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; diff --git a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart index e46568645f775..205e1b0653b4d 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart @@ -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()'; @@ -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; @@ -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; @@ -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';