From 5be7c0a28e56f6dc83959d1731582a622f0d4d25 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Fri, 19 Jan 2024 11:53:04 -0500 Subject: [PATCH 01/20] Intial add of country code, no tests --- .../android/build.gradle | 4 ++-- .../inapppurchase/MethodCallHandlerImpl.java | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/android/build.gradle b/packages/in_app_purchase/in_app_purchase_android/android/build.gradle index 9f6feebeaa8..7bddd6f9549 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/build.gradle +++ b/packages/in_app_purchase/in_app_purchase_android/android/build.gradle @@ -29,7 +29,7 @@ android { compileSdkVersion 33 defaultConfig { - minSdkVersion 16 + minSdkVersion 19 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } lintOptions { @@ -61,7 +61,7 @@ dependencies { // org.jetbrains.kotlin:kotlin-bom artifact purpose is to align kotlin stdlib and related code versions. // See: https://youtrack.jetbrains.com/issue/KT-55297/kotlin-stdlib-should-declare-constraints-on-kotlin-stdlib-jdk8-and-kotlin-stdlib-jdk7 implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.22")) - implementation 'com.android.billingclient:billing:6.0.1' + implementation 'com.android.billingclient:billing:6.1.0' testImplementation 'junit:junit:4.13.2' testImplementation 'org.json:json:20231013' testImplementation 'org.mockito:mockito-core:5.4.0' diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java index 514b2675a88..5b6c9bdc492 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java @@ -20,6 +20,8 @@ import androidx.annotation.VisibleForTesting; import com.android.billingclient.api.AcknowledgePurchaseParams; import com.android.billingclient.api.BillingClient; +import com.android.billingclient.api.BillingConfigResponseListener; +import com.android.billingclient.api.GetBillingConfigParams; import com.android.billingclient.api.BillingClientStateListener; import com.android.billingclient.api.BillingFlowParams; import com.android.billingclient.api.BillingResult; @@ -61,7 +63,8 @@ static final class MethodNames { static final String ACKNOWLEDGE_PURCHASE = "BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)"; static final String IS_FEATURE_SUPPORTED = "BillingClient#isFeatureSupported(String)"; - static final String GET_CONNECTION_STATE = "BillingClient#getConnectionState()"; + static final String GET_CONNECTION_STATE = "BillingClient#getConnectionState()";; + static final String GET_BILLING_CONFIG = "BillingClient#getBillingConfig()"; private MethodNames() {} } @@ -184,11 +187,25 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result case MethodNames.GET_CONNECTION_STATE: getConnectionState(result); break; + case MethodNames.GET_BILLING_CONFIG: + getBillingConfig(result); + break; default: result.notImplemented(); } } + private void getBillingConfig(final MethodChannel.Result result) { + billingClient.getBillingConfigAsync( + GetBillingConfigParams.newBuilder().build(), + (billingResult, billingConfig) -> { + final Map serialized = new HashMap<>(); + serialized.put("billingResult", fromBillingResult(billingResult)); + serialized.put("countryCode", billingConfig.getCountryCode()); + result.success(serialized); + }); + } + private void endConnection(final MethodChannel.Result result) { endBillingClientConnection(); result.success(null); From 5d6f1cc6e17226e01deb7069e4267169895bc37f Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Fri, 19 Jan 2024 12:27:52 -0500 Subject: [PATCH 02/20] Add tests for getBillingConfig --- .../inapppurchase/MethodCallHandlerTest.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java index 40aeb7ad68d..aa8652bebaf 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java @@ -7,6 +7,7 @@ import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.MethodNames.ACKNOWLEDGE_PURCHASE; import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.MethodNames.CONSUME_PURCHASE_ASYNC; import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.MethodNames.END_CONNECTION; +import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.MethodNames.GET_BILLING_CONFIG; import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.MethodNames.IS_FEATURE_SUPPORTED; import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.MethodNames.IS_READY; import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.MethodNames.LAUNCH_BILLING_FLOW; @@ -46,10 +47,13 @@ import com.android.billingclient.api.AcknowledgePurchaseResponseListener; import com.android.billingclient.api.BillingClient; import com.android.billingclient.api.BillingClientStateListener; +import com.android.billingclient.api.BillingConfig; +import com.android.billingclient.api.BillingConfigResponseListener; import com.android.billingclient.api.BillingFlowParams; import com.android.billingclient.api.BillingResult; import com.android.billingclient.api.ConsumeParams; import com.android.billingclient.api.ConsumeResponseListener; +import com.android.billingclient.api.GetBillingConfigParams; import com.android.billingclient.api.ProductDetails; import com.android.billingclient.api.ProductDetailsResponseListener; import com.android.billingclient.api.Purchase; @@ -90,6 +94,7 @@ public class MethodCallHandlerTest { @Mock Context context; @Mock ActivityPluginBinding mockActivityPluginBinding; @Captor ArgumentCaptor> resultCaptor; + @Mock BillingConfig mockBillingConfig; @Before public void setUp() { @@ -185,6 +190,33 @@ public void startConnection_multipleCalls() { verify(result, times(1)).success(any()); } + @Test + public void getBillingConfigSuccess() { + mockStartConnection(); + ArgumentCaptor paramsCaptor = + ArgumentCaptor.forClass(GetBillingConfigParams.class); + ArgumentCaptor listenerCaptor = + ArgumentCaptor.forClass(BillingConfigResponseListener.class); + MethodCall billingCall = new MethodCall(GET_BILLING_CONFIG, null); + methodChannelHandler.onMethodCall(billingCall, mock(Result.class)); + BillingResult billingResult = + BillingResult.newBuilder() + .setResponseCode(100) + .setDebugMessage("dummy debug message") + .build(); + final String expectedCountryCode = "US"; + final HashMap expectedResult = fromBillingResult(billingResult); + expectedResult.put("countryCode", expectedCountryCode); + + when(mockBillingConfig.getCountryCode()).thenReturn(expectedCountryCode); + doNothing().when(mockBillingClient).getBillingConfigAsync(paramsCaptor.capture(), listenerCaptor.capture()); + + methodChannelHandler.onMethodCall(billingCall, result); + listenerCaptor.getValue().onBillingConfigResponse(billingResult, mockBillingConfig); + + verify(result, times(1)).success(any()); + } + @Test public void endConnection() { // Set up a connected BillingClient instance From e19b6441c190bde8d050646d382c43ae165a94f4 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Fri, 19 Jan 2024 14:39:20 -0500 Subject: [PATCH 03/20] Formating --- .../in_app_purchase_android/android/build.gradle | 4 ++-- .../plugins/inapppurchase/MethodCallHandlerImpl.java | 3 +-- .../plugins/inapppurchase/MethodCallHandlerTest.java | 6 ++++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/android/build.gradle b/packages/in_app_purchase/in_app_purchase_android/android/build.gradle index 7bddd6f9549..1f761b3fed4 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/build.gradle +++ b/packages/in_app_purchase/in_app_purchase_android/android/build.gradle @@ -26,10 +26,10 @@ android { if (project.android.hasProperty("namespace")) { namespace 'io.flutter.plugins.inapppurchase' } - compileSdkVersion 33 + compileSdk 33 defaultConfig { - minSdkVersion 19 + minSdk 19 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } lintOptions { diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java index 5b6c9bdc492..dc64375017c 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java @@ -20,13 +20,12 @@ import androidx.annotation.VisibleForTesting; import com.android.billingclient.api.AcknowledgePurchaseParams; import com.android.billingclient.api.BillingClient; -import com.android.billingclient.api.BillingConfigResponseListener; -import com.android.billingclient.api.GetBillingConfigParams; import com.android.billingclient.api.BillingClientStateListener; import com.android.billingclient.api.BillingFlowParams; import com.android.billingclient.api.BillingResult; import com.android.billingclient.api.ConsumeParams; import com.android.billingclient.api.ConsumeResponseListener; +import com.android.billingclient.api.GetBillingConfigParams; import com.android.billingclient.api.ProductDetails; import com.android.billingclient.api.QueryProductDetailsParams; import com.android.billingclient.api.QueryProductDetailsParams.Product; diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java index aa8652bebaf..f6f87f019f5 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java @@ -205,11 +205,13 @@ public void getBillingConfigSuccess() { .setDebugMessage("dummy debug message") .build(); final String expectedCountryCode = "US"; - final HashMap expectedResult = fromBillingResult(billingResult); + final HashMap expectedResult = fromBillingResult(billingResult); expectedResult.put("countryCode", expectedCountryCode); when(mockBillingConfig.getCountryCode()).thenReturn(expectedCountryCode); - doNothing().when(mockBillingClient).getBillingConfigAsync(paramsCaptor.capture(), listenerCaptor.capture()); + doNothing() + .when(mockBillingClient) + .getBillingConfigAsync(paramsCaptor.capture(), listenerCaptor.capture()); methodChannelHandler.onMethodCall(billingCall, result); listenerCaptor.getValue().onBillingConfigResponse(billingResult, mockBillingConfig); From 3f5a4e3384f7bb3e20f2a72bf665a27822b911ec Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Wed, 24 Jan 2024 14:28:04 -0500 Subject: [PATCH 04/20] Manipulate data in translator class instead of impl --- .../plugins/inapppurchase/MethodCallHandlerImpl.java | 6 ++---- .../java/io/flutter/plugins/inapppurchase/Translator.java | 7 +++++++ .../plugins/inapppurchase/MethodCallHandlerTest.java | 3 ++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java index dc64375017c..ba90f2559e2 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java @@ -4,6 +4,7 @@ package io.flutter.plugins.inapppurchase; +import static io.flutter.plugins.inapppurchase.Translator.fromBillingConfig; import static io.flutter.plugins.inapppurchase.Translator.fromBillingResult; import static io.flutter.plugins.inapppurchase.Translator.fromProductDetailsList; import static io.flutter.plugins.inapppurchase.Translator.fromPurchaseHistoryRecordList; @@ -198,10 +199,7 @@ private void getBillingConfig(final MethodChannel.Result result) { billingClient.getBillingConfigAsync( GetBillingConfigParams.newBuilder().build(), (billingResult, billingConfig) -> { - final Map serialized = new HashMap<>(); - serialized.put("billingResult", fromBillingResult(billingResult)); - serialized.put("countryCode", billingConfig.getCountryCode()); - result.success(serialized); + result.success(fromBillingConfig(billingResult, billingConfig)); }); } diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java index 9f397e4e9fb..370e861fb2b 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java @@ -7,6 +7,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.billingclient.api.AccountIdentifiers; +import com.android.billingclient.api.BillingConfig; import com.android.billingclient.api.BillingResult; import com.android.billingclient.api.ProductDetails; import com.android.billingclient.api.Purchase; @@ -231,6 +232,12 @@ static HashMap fromBillingResult(BillingResult billingResult) { return info; } + static HashMap fromBillingConfig(BillingResult result, BillingConfig billingConfig) { + HashMap info = fromBillingResult(result); + info.put("countryCode", billingConfig.getCountryCode()); + return info; + } + /** * Gets the symbol of for the given currency code for the default {@link Locale.Category#DISPLAY * DISPLAY} locale. For example, for the US Dollar, the symbol is "$" if the default locale is the diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java index f6f87f019f5..2a826150a64 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/MethodCallHandlerTest.java @@ -17,6 +17,7 @@ import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.MethodNames.QUERY_PURCHASE_HISTORY_ASYNC; import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.MethodNames.START_CONNECTION; import static io.flutter.plugins.inapppurchase.PluginPurchaseListener.ON_PURCHASES_UPDATED; +import static io.flutter.plugins.inapppurchase.Translator.fromBillingConfig; import static io.flutter.plugins.inapppurchase.Translator.fromBillingResult; import static io.flutter.plugins.inapppurchase.Translator.fromProductDetailsList; import static io.flutter.plugins.inapppurchase.Translator.fromPurchaseHistoryRecordList; @@ -216,7 +217,7 @@ public void getBillingConfigSuccess() { methodChannelHandler.onMethodCall(billingCall, result); listenerCaptor.getValue().onBillingConfigResponse(billingResult, mockBillingConfig); - verify(result, times(1)).success(any()); + verify(result, times(1)).success(fromBillingConfig(billingResult, mockBillingConfig)); } @Test From 337a7d7f4ec86b46714160b66876994bfa682cef Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Wed, 24 Jan 2024 15:58:59 -0500 Subject: [PATCH 05/20] Add dart side code to call getBillingConfig and conversion tests --- .../plugins/inapppurchase/Translator.java | 3 + .../billing_client_wrapper.dart | 12 +++ .../billing_config_wrapper.dart | 74 +++++++++++++++++++ .../billing_config_wrapper.g.dart | 15 ++++ ...pp_purchase_android_platform_addition.dart | 8 ++ .../billing_client_wrapper_test.dart | 34 +++++++++ .../purchase_wrapper_test.dart | 10 +++ 7 files changed, 156 insertions(+) create mode 100644 packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart create mode 100644 packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.g.dart diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java index 370e861fb2b..504e6200b20 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java @@ -232,6 +232,9 @@ static HashMap fromBillingResult(BillingResult billingResult) { return info; } + /** + * Converter from {@link BillingResult} and {@link BillingConfig} to map. + */ static HashMap fromBillingConfig(BillingResult result, BillingConfig billingConfig) { HashMap info = fromBillingResult(result); info.put("countryCode", billingConfig.getCountryCode()); 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 12067d51451..05de5f0430f 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 @@ -10,6 +10,7 @@ import 'package:json_annotation/json_annotation.dart'; import '../../billing_client_wrappers.dart'; import '../channel.dart'; +import 'billing_config_wrapper.dart'; part 'billing_client_wrapper.g.dart'; @@ -324,6 +325,17 @@ class BillingClient { return result ?? false; } + @visibleForTesting + final String getBillingConfigMethodString = + 'BillingClient#getBillingConfig()'; + + /// TODO + Future getBillingConfig() async { + return BillingConfigWrapper.fromJson((await channel + .invokeMapMethod(getBillingConfigMethodString)) ?? + {}); + } + /// The method call handler for [channel]. @visibleForTesting Future callHandler(MethodCall call) async { diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart new file mode 100644 index 00000000000..29ae091a93a --- /dev/null +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart @@ -0,0 +1,74 @@ +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/material.dart'; +import 'package:json_annotation/json_annotation.dart'; + +import '../../billing_client_wrappers.dart'; + +// WARNING: Changes to `@JsonSerializable` classes need to be reflected in the +// below generated file. Run `flutter packages pub run build_runner watch` to +// rebuild and watch for further changes. +part 'billing_config_wrapper.g.dart'; + +/// The error message shown when the map represents billing config is invalid from method channel. +/// +/// This usually indicates a serious underlining code issue in the plugin. +@visibleForTesting +const String kInvalidBillingConfigErrorMessage = + 'Invalid billing config map from method channel.'; + +/// Params containing the response code and the debug message from the Play Billing API response. +@JsonSerializable() +@BillingResponseConverter() +@immutable +class BillingConfigWrapper implements HasBillingResponse { + /// Constructs the object with [responseCode] and [debugMessage]. + const BillingConfigWrapper({required this.responseCode, this.debugMessage, this.countryCode}); + + /// Constructs an instance of this from a key value map of data. + /// + /// The map needs to have named string keys with values matching the names and + /// types of all of the members on this class. + factory BillingConfigWrapper.fromJson(Map? map) { + if (map == null || map.isEmpty) { + return const BillingConfigWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingResultErrorMessage, + countryCode: '', + ); + } + return _$BillingConfigWrapperFromJson(map); + } + + /// Response code returned in the Play Billing API calls. + @override + final BillingResponse responseCode; + + /// Debug message returned in the Play Billing API calls. + /// + /// Defaults to `null`. + /// This message uses an en-US locale and should not be shown to users. + @JsonKey(defaultValue: '') + final String? debugMessage; + + /// https://developer.android.com/reference/com/android/billingclient/api/BillingConfig#getCountryCode() + @JsonKey(defaultValue: '') + final String? countryCode; + + @override + bool operator ==(Object other) { + if (other.runtimeType != runtimeType) { + return false; + } + + return other is BillingConfigWrapper && + other.responseCode == responseCode && + other.debugMessage == debugMessage && + other.countryCode == countryCode; + } + + @override + int get hashCode => Object.hash(responseCode, debugMessage, countryCode); +} \ No newline at end of file diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.g.dart new file mode 100644 index 00000000000..21f98577d91 --- /dev/null +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.g.dart @@ -0,0 +1,15 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'billing_config_wrapper.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +BillingConfigWrapper _$BillingConfigWrapperFromJson(Map json) => + BillingConfigWrapper( + responseCode: const BillingResponseConverter() + .fromJson(json['responseCode'] as int?), + debugMessage: json['debugMessage'] as String? ?? '', + countryCode: json['countryCode'] as String? ?? '', + ); diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart index e3050f8888b..3dd114d5a81 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart @@ -7,6 +7,7 @@ import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_inte import '../billing_client_wrappers.dart'; import '../in_app_purchase_android.dart'; +import 'billing_client_wrappers/billing_config_wrapper.dart'; /// Contains InApp Purchase features that are only available on PlayStore. class InAppPurchaseAndroidPlatformAddition @@ -146,4 +147,11 @@ class InAppPurchaseAndroidPlatformAddition (BillingClient client) => client.isFeatureSupported(feature), ); } + + /// TODO + Future getBillingConfig() async { + return _billingClientManager.runWithClientNonRetryable( + (BillingClient client) => client.getBillingConfig(), + ); + } } 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 a840bd2d060..bf7372dac66 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 @@ -5,6 +5,7 @@ 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/src/billing_client_wrappers/billing_config_wrapper.dart'; import 'package:in_app_purchase_android/src/channel.dart'; import '../stub_in_app_purchase_platform.dart'; @@ -641,6 +642,39 @@ void main() { expect(arguments['feature'], equals('subscriptions')); }); }); + + group('billingConfig', () { + const String billingConfigMethodName = 'BillingClient#getBillingConfig()'; + test('billingConfig returns object', () async { + late Map arguments; + stubPlatform.addResponse( + name: billingConfigMethodName, + value: const BillingConfigWrapper( + countryCode: 'US', + responseCode: BillingResponse.ok, + debugMessage: ''), + additionalStepBeforeReturn: (dynamic value) => + arguments = value as Map, + ); + final BillingConfigWrapper result = + await billingClient.getBillingConfig(); + expect(result.countryCode, 'US'); + }); + + + test('handles method channel returning null', () async { + stubPlatform.addResponse( + name: billingConfigMethodName, + ); + final BillingConfigWrapper result = + await billingClient.getBillingConfig(); + expect( + result, + equals(const BillingConfigWrapper( + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingConfigErrorMessage))); + }); + }); } /// This allows a value of type T or T? to be treated as a value of type T?. diff --git a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart index 14cd446bf8a..6b20a92c8e7 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart @@ -4,6 +4,7 @@ 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_android/src/billing_client_wrappers/billing_config_wrapper.dart'; import 'package:test/test.dart'; const PurchaseWrapper dummyPurchase = PurchaseWrapper( @@ -252,3 +253,12 @@ Map buildBillingResultMap(BillingResultWrapper original) { 'debugMessage': original.debugMessage, }; } + +Map buildBillingConfigMap(BillingConfigWrapper original) { + return { + 'responseCode': + const BillingResponseConverter().toJson(original.responseCode), + 'debugMessage': original.debugMessage, + 'countryCode': original.countryCode, + }; +} \ No newline at end of file From 99af52968ab5077138ef997aa1983a75cc27fe23 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Thu, 25 Jan 2024 10:20:31 -0500 Subject: [PATCH 06/20] Correct null test to include empty country code, fix non null billing config test to return map not object --- .../billing_client_wrapper.dart | 1 + .../billing_config_wrapper.dart | 2 +- .../billing_client_wrapper_test.dart | 18 +++++++++--------- 3 files changed, 11 insertions(+), 10 deletions(-) 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 05de5f0430f..4480de312f8 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 @@ -325,6 +325,7 @@ class BillingClient { return result ?? false; } + /// TODO @visibleForTesting final String getBillingConfigMethodString = 'BillingClient#getBillingConfig()'; diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart index 29ae091a93a..591444d56bb 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart @@ -71,4 +71,4 @@ class BillingConfigWrapper implements HasBillingResponse { @override int get hashCode => Object.hash(responseCode, debugMessage, countryCode); -} \ No newline at end of file +} 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 bf7372dac66..2a2c86dd813 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 @@ -646,22 +646,20 @@ void main() { group('billingConfig', () { const String billingConfigMethodName = 'BillingClient#getBillingConfig()'; test('billingConfig returns object', () async { - late Map arguments; + const BillingConfigWrapper expected = BillingConfigWrapper( + countryCode: 'US', + responseCode: BillingResponse.ok, + debugMessage: ''); stubPlatform.addResponse( name: billingConfigMethodName, - value: const BillingConfigWrapper( - countryCode: 'US', - responseCode: BillingResponse.ok, - debugMessage: ''), - additionalStepBeforeReturn: (dynamic value) => - arguments = value as Map, + value: buildBillingConfigMap(expected), ); final BillingConfigWrapper result = await billingClient.getBillingConfig(); expect(result.countryCode, 'US'); + expect(result, expected); }); - test('handles method channel returning null', () async { stubPlatform.addResponse( name: billingConfigMethodName, @@ -672,7 +670,9 @@ void main() { result, equals(const BillingConfigWrapper( responseCode: BillingResponse.error, - debugMessage: kInvalidBillingConfigErrorMessage))); + debugMessage: kInvalidBillingConfigErrorMessage, + countryCode: '', + ))); }); }); } From fdc42cdb881ad4e70267f5661d03f833e901785b Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Thu, 25 Jan 2024 12:05:39 -0500 Subject: [PATCH 07/20] move buildBillingConfigMap to the class that uses it --- .../billing_client_wrappers/billing_config_wrapper.dart | 2 +- .../billing_client_wrapper_test.dart | 9 +++++++++ .../billing_client_wrappers/purchase_wrapper_test.dart | 9 --------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart index 591444d56bb..6011e22237f 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart @@ -35,7 +35,7 @@ class BillingConfigWrapper implements HasBillingResponse { if (map == null || map.isEmpty) { return const BillingConfigWrapper( responseCode: BillingResponse.error, - debugMessage: kInvalidBillingResultErrorMessage, + debugMessage: kInvalidBillingConfigErrorMessage, countryCode: '', ); } 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 2a2c86dd813..2ce22f11b2c 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 @@ -677,6 +677,15 @@ void main() { }); } +Map buildBillingConfigMap(BillingConfigWrapper original) { + return { + 'responseCode': + const BillingResponseConverter().toJson(original.responseCode), + 'debugMessage': original.debugMessage, + 'countryCode': original.countryCode, + }; +} + /// This allows a value of type T or T? to be treated as a value of type T?. /// /// We use this so that APIs that have become non-nullable can still be used diff --git a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart index 6b20a92c8e7..146c77220b9 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart @@ -253,12 +253,3 @@ Map buildBillingResultMap(BillingResultWrapper original) { 'debugMessage': original.debugMessage, }; } - -Map buildBillingConfigMap(BillingConfigWrapper original) { - return { - 'responseCode': - const BillingResponseConverter().toJson(original.responseCode), - 'debugMessage': original.debugMessage, - 'countryCode': original.countryCode, - }; -} \ No newline at end of file From 036e2f24f23494b4e824fa50929c2ea7a6492d1b Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Thu, 25 Jan 2024 12:34:43 -0500 Subject: [PATCH 08/20] Write documentation and remove todos, remove unused import --- .../billing_client_wrappers/billing_client_wrapper.dart | 7 +++++-- .../billing_client_wrappers/billing_config_wrapper.dart | 4 ++-- .../src/in_app_purchase_android_platform_addition.dart | 9 ++++++--- .../billing_client_wrappers/purchase_wrapper_test.dart | 1 - 4 files changed, 13 insertions(+), 8 deletions(-) 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 4480de312f8..c54fc54e91b 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 @@ -325,12 +325,15 @@ class BillingClient { return result ?? false; } - /// TODO + /// BillingConfig method channel string identifier. + // + // Must match the value of GET_BILLING_CONFIG in + // ../../../android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java @visibleForTesting final String getBillingConfigMethodString = 'BillingClient#getBillingConfig()'; - /// TODO + /// Fetches billing config info into a [BillingConfigWrapper] object. Future getBillingConfig() async { return BillingConfigWrapper.fromJson((await channel .invokeMapMethod(getBillingConfigMethodString)) ?? diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart index 6011e22237f..8c1ca370d58 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart @@ -25,7 +25,7 @@ const String kInvalidBillingConfigErrorMessage = @immutable class BillingConfigWrapper implements HasBillingResponse { /// Constructs the object with [responseCode] and [debugMessage]. - const BillingConfigWrapper({required this.responseCode, this.debugMessage, this.countryCode}); + const BillingConfigWrapper({required this.responseCode, this.debugMessage, this.countryCode = ''}); /// Constructs an instance of this from a key value map of data. /// @@ -55,7 +55,7 @@ class BillingConfigWrapper implements HasBillingResponse { /// https://developer.android.com/reference/com/android/billingclient/api/BillingConfig#getCountryCode() @JsonKey(defaultValue: '') - final String? countryCode; + final String countryCode; @override bool operator ==(Object other) { diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart index 3dd114d5a81..bcaf5f1b8cc 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart @@ -148,10 +148,13 @@ class InAppPurchaseAndroidPlatformAddition ); } - /// TODO - Future getBillingConfig() async { + /// Returns Play billing country code based on ISO-3166-1 alpha2 format. + /// + /// See: https://developer.android.com/reference/com/android/billingclient/api/BillingConfig + /// See: https://unicode.org/cldr/charts/latest/supplemental/territory_containment_un_m_49.html + Future getBillingConfig() async { return _billingClientManager.runWithClientNonRetryable( - (BillingClient client) => client.getBillingConfig(), + (BillingClient client) async => (await client.getBillingConfig()).countryCode, ); } } diff --git a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart index 146c77220b9..14cd446bf8a 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/billing_client_wrappers/purchase_wrapper_test.dart @@ -4,7 +4,6 @@ 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_android/src/billing_client_wrappers/billing_config_wrapper.dart'; import 'package:test/test.dart'; const PurchaseWrapper dummyPurchase = PurchaseWrapper( From 91950f3e540e605d712078a1520bd4e89052673a Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Thu, 25 Jan 2024 12:49:47 -0500 Subject: [PATCH 09/20] Analyzer warnings --- .../lib/src/billing_client_wrappers/billing_config_wrapper.dart | 1 - .../lib/src/in_app_purchase_android_platform_addition.dart | 1 - .../billing_client_wrappers/billing_client_wrapper_test.dart | 1 - 3 files changed, 3 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart index 8c1ca370d58..14a0a69cc0c 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart @@ -36,7 +36,6 @@ class BillingConfigWrapper implements HasBillingResponse { return const BillingConfigWrapper( responseCode: BillingResponse.error, debugMessage: kInvalidBillingConfigErrorMessage, - countryCode: '', ); } return _$BillingConfigWrapperFromJson(map); diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart index bcaf5f1b8cc..ef44487fa73 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart @@ -7,7 +7,6 @@ import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_inte import '../billing_client_wrappers.dart'; import '../in_app_purchase_android.dart'; -import 'billing_client_wrappers/billing_config_wrapper.dart'; /// Contains InApp Purchase features that are only available on PlayStore. class InAppPurchaseAndroidPlatformAddition 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 2ce22f11b2c..32caad0269f 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 @@ -671,7 +671,6 @@ void main() { equals(const BillingConfigWrapper( responseCode: BillingResponse.error, debugMessage: kInvalidBillingConfigErrorMessage, - countryCode: '', ))); }); }); From 5cd0acbf5b00eb5b61e363892c2c502ba8b19df3 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Thu, 25 Jan 2024 15:19:56 -0500 Subject: [PATCH 10/20] java format warnings --- .../io/flutter/plugins/inapppurchase/Translator.java | 7 +++---- .../billing_client_wrappers/billing_config_wrapper.dart | 9 +++++---- .../src/in_app_purchase_android_platform_addition.dart | 3 ++- .../billing_client_wrapper_test.dart | 6 +++--- 4 files changed, 13 insertions(+), 12 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java index 504e6200b20..95976d1a8af 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java @@ -232,10 +232,9 @@ static HashMap fromBillingResult(BillingResult billingResult) { return info; } - /** - * Converter from {@link BillingResult} and {@link BillingConfig} to map. - */ - static HashMap fromBillingConfig(BillingResult result, BillingConfig billingConfig) { + /** Converter from {@link BillingResult} and {@link BillingConfig} to map. */ + static HashMap fromBillingConfig( + BillingResult result, BillingConfig billingConfig) { HashMap info = fromBillingResult(result); info.put("countryCode", billingConfig.getCountryCode()); return info; diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart index 14a0a69cc0c..27601285bc1 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_config_wrapper.dart @@ -25,7 +25,8 @@ const String kInvalidBillingConfigErrorMessage = @immutable class BillingConfigWrapper implements HasBillingResponse { /// Constructs the object with [responseCode] and [debugMessage]. - const BillingConfigWrapper({required this.responseCode, this.debugMessage, this.countryCode = ''}); + const BillingConfigWrapper( + {required this.responseCode, this.debugMessage, this.countryCode = ''}); /// Constructs an instance of this from a key value map of data. /// @@ -34,9 +35,9 @@ class BillingConfigWrapper implements HasBillingResponse { factory BillingConfigWrapper.fromJson(Map? map) { if (map == null || map.isEmpty) { return const BillingConfigWrapper( - responseCode: BillingResponse.error, - debugMessage: kInvalidBillingConfigErrorMessage, - ); + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingConfigErrorMessage, + ); } return _$BillingConfigWrapperFromJson(map); } diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart index ef44487fa73..933c2cdcd76 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart @@ -153,7 +153,8 @@ class InAppPurchaseAndroidPlatformAddition /// See: https://unicode.org/cldr/charts/latest/supplemental/territory_containment_un_m_49.html Future getBillingConfig() async { return _billingClientManager.runWithClientNonRetryable( - (BillingClient client) async => (await client.getBillingConfig()).countryCode, + (BillingClient client) async => + (await client.getBillingConfig()).countryCode, ); } } 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 32caad0269f..74d18bf79bc 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 @@ -669,9 +669,9 @@ void main() { expect( result, equals(const BillingConfigWrapper( - responseCode: BillingResponse.error, - debugMessage: kInvalidBillingConfigErrorMessage, - ))); + responseCode: BillingResponse.error, + debugMessage: kInvalidBillingConfigErrorMessage, + ))); }); }); } From 894473c47c48b5346112291757e5614f16267ef1 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Thu, 25 Jan 2024 15:26:41 -0500 Subject: [PATCH 11/20] Version code change --- packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md | 3 ++- packages/in_app_purchase/in_app_purchase_android/pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) 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 10fcd8d76b3..7acf31dc171 100644 --- a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md @@ -1,5 +1,6 @@ -## NEXT +## 0.3.0+18 +* Adds country code api for android. * Updates compileSdk version to 34. ## 0.3.0+17 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 ff023ce5142..d97518aa751 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+17 +version: 0.3.0+18 environment: sdk: ">=3.0.0 <4.0.0" From e33f22c2ad1a369cfb384cf8a11f765daa9b01ed Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Fri, 26 Jan 2024 12:58:17 -0500 Subject: [PATCH 12/20] Restore in app purchase instructions in example readme from bad PR https://github.com/flutter/plugins/pull/6459 --- .../in_app_purchase_android/example/README.md | 58 ++++++++++++++ .../example/README.md | 76 +++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/packages/in_app_purchase/in_app_purchase_android/example/README.md b/packages/in_app_purchase/in_app_purchase_android/example/README.md index 96b8bb17dbf..1fc0c95290f 100644 --- a/packages/in_app_purchase/in_app_purchase_android/example/README.md +++ b/packages/in_app_purchase/in_app_purchase_android/example/README.md @@ -7,3 +7,61 @@ package. Unless you are making changes to this implementation package, this example is very unlikely to be relevant. + +# In App Purchase Example + +Demonstrates how to use the In App Purchase Android (IAP) Plugin. + +## Getting Started + +### Preparation + +There's a significant amount of setup required for testing in-app purchases +successfully, including registering new app IDs and store entries to use for +testing in the Play Developer Console. Google Play requires developers to +configure an app with in-app items for purchase to call their in-app-purchase +APIs. The Google Play Store has extensive documentation on how to do this, and +we've also included a high level guide below. + +* [Google Play Billing Overview](https://developer.android.com/google/play/billing/billing_overview) + +### Android + +1. Create a new app in the [Play Developer + Console](https://play.google.com/apps/publish/) (PDC). + +2. Sign up for a merchant's account in the PDC. + +3. Create IAPs in the PDC available for purchase in the app. The example assumes + the following SKU IDs exist: + + - `consumable`: A managed product. + - `upgrade`: A managed product. + - `subscription_silver`: A lower level subscription. + - `subscription_gold`: A higher level subscription. + + Make sure that all of the products are set to `ACTIVE`. + +4. Update `APP_ID` in `example/android/app/build.gradle` to match your package + ID in the PDC. + +5. Create an `example/android/keystore.properties` file with all your signing + information. `keystore.example.properties` exists as an example to follow. + It's impossible to use any of the `BillingClient` APIs from an unsigned APK. + See + [here](https://developer.android.com/studio/publish/app-signing#secure-shared-keystore) + and [here](https://developer.android.com/studio/publish/app-signing#sign-apk) + for more information. + +6. Build a signed apk. `flutter build apk` will work for this, the gradle files + in this project have been configured to sign even debug builds. + +7. Upload the signed APK from step 6 to the PDC, and publish that to the alpha + test channel. Add your test account as an approved tester. The + `BillingClient` APIs won't work unless the app has been fully published to + the alpha channel and is being used by an authorized test account. See + [here](https://support.google.com/googleplay/android-developer/answer/3131213) + for more info. + +8. Sign in to the test device with the test account from step #7. Then use + `flutter run` to install the app to the device and test like normal. diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/README.md b/packages/in_app_purchase/in_app_purchase_storekit/example/README.md index 96b8bb17dbf..49d44583a94 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/example/README.md +++ b/packages/in_app_purchase/in_app_purchase_storekit/example/README.md @@ -7,3 +7,79 @@ package. Unless you are making changes to this implementation package, this example is very unlikely to be relevant. + +# In App Purchase iOS Example + +Demonstrates how to use the In App Purchase iOS (IAP) Plugin. + +## Getting Started + +### Preparation + +There's a significant amount of setup required for testing in app purchases +successfully, including registering new app IDs and store entries to use for +testing in App Store Connect. The App Store requires developers to configure +an app with in-app items for purchase to call their in-app-purchase APIs. +The App Store has extensive documentation on how to do this, and we've also +included a high level guide below. + +* [In-App Purchase (App Store)](https://developer.apple.com/in-app-purchase/) + +### iOS + +When using Xcode 12 and iOS 14 or higher you can run the example in the simulator or on a device without +having to configure an App in App Store Connect. The example app is set up to use StoreKit Testing configured +in the `example/ios/Runner/Configuration.storekit` file (as documented in the article [Setting Up StoreKit Testing in Xcode](https://developer.apple.com/documentation/xcode/setting_up_storekit_testing_in_xcode?language=objc)). +To run the application take the following steps (note that it will only work when running from Xcode): + +1. Open the example app with Xcode, `File > Open File` `example/ios/Runner.xcworkspace`; + +2. Within Xcode edit the current scheme, `Product > Scheme > Edit Scheme...` (or press `Command + Shift + ,`); + +3. Enable StoreKit testing: + a. Select the `Run` action; + b. Click `Options` in the action settings; + c. Select the `Configuration.storekit` for the StoreKit Configuration option. + +4. Click the `Close` button to close the scheme editor; + +5. Select the device you want to run the example App on; + +6. Run the application using `Product > Run` (or hit the run button). + +When testing on pre-iOS 14 you can't run the example app on a simulator and you will need to configure an app in App Store Connect. You can do so by following the steps below: + +1. Follow ["Workflow for configuring in-app + purchases"](https://help.apple.com/app-store-connect/#/devb57be10e7), a + detailed guide on all the steps needed to enable IAPs for an app. Complete + steps 1 ("Sign a Paid Applications Agreement") and 2 ("Configure in-app + purchases"). + + For step #2, "Configure in-app purchases in App Store Connect," you'll want + to create the following products: + + - A consumable with product ID `consumable` + - An upgrade with product ID `upgrade` + - An auto-renewing subscription with product ID `subscription_silver` + - An non-renewing subscription with product ID `subscription_gold` + +2. In XCode, `File > Open File` `example/ios/Runner.xcworkspace`. Update the + Bundle ID to match the Bundle ID of the app created in step #1. + +3. [Create a Sandbox tester + account](https://help.apple.com/app-store-connect/#/dev8b997bee1) to test the + in-app purchases with. + +4. Use `flutter run` to install the app and test it. Note that you need to test + it on a real device instead of a simulator. Next click on one of the products + in the example App, this enables the "SANDBOX ACCOUNT" section in the iOS + settings. You will now be asked to sign in with your sandbox test account to + complete the purchase (no worries you won't be charged). If for some reason + you aren't asked to sign-in or the wrong user is listed, go into the iOS + settings ("Settings" -> "App Store" -> "SANDBOX ACCOUNT") and update your + sandbox account from there. This procedure is explained in great detail in + the [Testing In-App Purchases with Sandbox](https://developer.apple.com/documentation/storekit/in-app_purchase/testing_in-app_purchases_with_sandbox?language=objc) article. + + +**Important:** signing into any production service (including iTunes!) with the +sandbox test account will permanently invalidate it. From 1dc004b77a96854fbf62070fe6dbab3bc8904b3f Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Fri, 26 Jan 2024 13:21:14 -0500 Subject: [PATCH 13/20] Update packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java Co-authored-by: Gray Mackall <34871572+gmackall@users.noreply.github.com> --- .../io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java index ba90f2559e2..247e037d320 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java @@ -63,7 +63,7 @@ static final class MethodNames { static final String ACKNOWLEDGE_PURCHASE = "BillingClient#acknowledgePurchase(AcknowledgePurchaseParams, AcknowledgePurchaseResponseListener)"; static final String IS_FEATURE_SUPPORTED = "BillingClient#isFeatureSupported(String)"; - static final String GET_CONNECTION_STATE = "BillingClient#getConnectionState()";; + static final String GET_CONNECTION_STATE = "BillingClient#getConnectionState()"; static final String GET_BILLING_CONFIG = "BillingClient#getBillingConfig()"; private MethodNames() {} From 319ffe7eb476034b2b045a5f56aad33ac7d1bcee Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Fri, 26 Jan 2024 13:48:31 -0500 Subject: [PATCH 14/20] Add example app code that shows country code in UI rename addition api to getCountryCode --- .../example/lib/main.dart | 20 +++++++++++++++---- ...pp_purchase_android_platform_addition.dart | 2 +- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/example/lib/main.dart b/packages/in_app_purchase/in_app_purchase_android/example/lib/main.dart index 6377d2dc575..d3eafa8d715 100644 --- a/packages/in_app_purchase/in_app_purchase_android/example/lib/main.dart +++ b/packages/in_app_purchase/in_app_purchase_android/example/lib/main.dart @@ -48,6 +48,7 @@ class _MyAppState extends State<_MyApp> { List _products = []; List _purchases = []; List _consumables = []; + String _countryCode = ''; bool _isAvailable = false; bool _purchasePending = false; bool _loading = true; @@ -228,6 +229,11 @@ class _MyAppState extends State<_MyApp> { 'This app needs special configuration to run. Please see example/README.md for instructions.'))); } + productList.add(ListTile( + title: Text('User Country Code', + style: TextStyle(color: ThemeData.light().colorScheme.error)), + subtitle: Text(_countryCode))); + // This loading previous purchases code is just a demo. Please do not use this as it is. // In your app you should always verify the purchase data using the `verificationData` inside the [PurchaseDetails] object before trusting it. // We recommend that you use your own server to verify the purchase data. @@ -346,6 +352,12 @@ class _MyAppState extends State<_MyApp> { }); } + Future deliverCountryCode(String countryCode) async { + setState(() { + _countryCode = countryCode; + }); + } + Future deliverProduct(PurchaseDetails purchaseDetails) async { // IMPORTANT!! Always verify purchase details before delivering the product. if (purchaseDetails.productID == _kConsumableId) { @@ -385,6 +397,10 @@ class _MyAppState extends State<_MyApp> { if (purchaseDetails.status == PurchaseStatus.pending) { showPendingUI(); } else { + final InAppPurchaseAndroidPlatformAddition addition = + InAppPurchasePlatformAddition.instance! + as InAppPurchaseAndroidPlatformAddition; + unawaited(deliverCountryCode(await addition.getCountryCode())); if (purchaseDetails.status == PurchaseStatus.error) { handleError(purchaseDetails.error!); } else if (purchaseDetails.status == PurchaseStatus.purchased || @@ -399,10 +415,6 @@ class _MyAppState extends State<_MyApp> { } if (!_kAutoConsume && purchaseDetails.productID == _kConsumableId) { - final InAppPurchaseAndroidPlatformAddition addition = - InAppPurchasePlatformAddition.instance! - as InAppPurchaseAndroidPlatformAddition; - await addition.consumePurchase(purchaseDetails); } diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart index 933c2cdcd76..de27cbbc69e 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart @@ -151,7 +151,7 @@ class InAppPurchaseAndroidPlatformAddition /// /// See: https://developer.android.com/reference/com/android/billingclient/api/BillingConfig /// See: https://unicode.org/cldr/charts/latest/supplemental/territory_containment_un_m_49.html - Future getBillingConfig() async { + Future getCountryCode() async { return _billingClientManager.runWithClientNonRetryable( (BillingClient client) async => (await client.getBillingConfig()).countryCode, From 28e95ad1e05d1fa809ed792b81c158c86f53764a Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Mon, 29 Jan 2024 11:41:35 -0500 Subject: [PATCH 15/20] Remove "Demonstrates how to use" verbiage since that is confusing while leaving instructions for how to test --- .../in_app_purchase/in_app_purchase_android/example/README.md | 4 ---- .../in_app_purchase_storekit/example/README.md | 4 ---- 2 files changed, 8 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/example/README.md b/packages/in_app_purchase/in_app_purchase_android/example/README.md index 1fc0c95290f..ed5b4d6be70 100644 --- a/packages/in_app_purchase/in_app_purchase_android/example/README.md +++ b/packages/in_app_purchase/in_app_purchase_android/example/README.md @@ -10,10 +10,6 @@ very unlikely to be relevant. # In App Purchase Example -Demonstrates how to use the In App Purchase Android (IAP) Plugin. - -## Getting Started - ### Preparation There's a significant amount of setup required for testing in-app purchases diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/README.md b/packages/in_app_purchase/in_app_purchase_storekit/example/README.md index 49d44583a94..c3cfef364eb 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/example/README.md +++ b/packages/in_app_purchase/in_app_purchase_storekit/example/README.md @@ -10,10 +10,6 @@ very unlikely to be relevant. # In App Purchase iOS Example -Demonstrates how to use the In App Purchase iOS (IAP) Plugin. - -## Getting Started - ### Preparation There's a significant amount of setup required for testing in app purchases From d7934fc8a6f89ad9af29c36507d10dde5805d73c Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Tue, 30 Jan 2024 14:46:27 -0500 Subject: [PATCH 16/20] Remove changes to ios readme --- .../example/README.md | 72 ------------------- 1 file changed, 72 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/README.md b/packages/in_app_purchase/in_app_purchase_storekit/example/README.md index c3cfef364eb..96b8bb17dbf 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/example/README.md +++ b/packages/in_app_purchase/in_app_purchase_storekit/example/README.md @@ -7,75 +7,3 @@ package. Unless you are making changes to this implementation package, this example is very unlikely to be relevant. - -# In App Purchase iOS Example - -### Preparation - -There's a significant amount of setup required for testing in app purchases -successfully, including registering new app IDs and store entries to use for -testing in App Store Connect. The App Store requires developers to configure -an app with in-app items for purchase to call their in-app-purchase APIs. -The App Store has extensive documentation on how to do this, and we've also -included a high level guide below. - -* [In-App Purchase (App Store)](https://developer.apple.com/in-app-purchase/) - -### iOS - -When using Xcode 12 and iOS 14 or higher you can run the example in the simulator or on a device without -having to configure an App in App Store Connect. The example app is set up to use StoreKit Testing configured -in the `example/ios/Runner/Configuration.storekit` file (as documented in the article [Setting Up StoreKit Testing in Xcode](https://developer.apple.com/documentation/xcode/setting_up_storekit_testing_in_xcode?language=objc)). -To run the application take the following steps (note that it will only work when running from Xcode): - -1. Open the example app with Xcode, `File > Open File` `example/ios/Runner.xcworkspace`; - -2. Within Xcode edit the current scheme, `Product > Scheme > Edit Scheme...` (or press `Command + Shift + ,`); - -3. Enable StoreKit testing: - a. Select the `Run` action; - b. Click `Options` in the action settings; - c. Select the `Configuration.storekit` for the StoreKit Configuration option. - -4. Click the `Close` button to close the scheme editor; - -5. Select the device you want to run the example App on; - -6. Run the application using `Product > Run` (or hit the run button). - -When testing on pre-iOS 14 you can't run the example app on a simulator and you will need to configure an app in App Store Connect. You can do so by following the steps below: - -1. Follow ["Workflow for configuring in-app - purchases"](https://help.apple.com/app-store-connect/#/devb57be10e7), a - detailed guide on all the steps needed to enable IAPs for an app. Complete - steps 1 ("Sign a Paid Applications Agreement") and 2 ("Configure in-app - purchases"). - - For step #2, "Configure in-app purchases in App Store Connect," you'll want - to create the following products: - - - A consumable with product ID `consumable` - - An upgrade with product ID `upgrade` - - An auto-renewing subscription with product ID `subscription_silver` - - An non-renewing subscription with product ID `subscription_gold` - -2. In XCode, `File > Open File` `example/ios/Runner.xcworkspace`. Update the - Bundle ID to match the Bundle ID of the app created in step #1. - -3. [Create a Sandbox tester - account](https://help.apple.com/app-store-connect/#/dev8b997bee1) to test the - in-app purchases with. - -4. Use `flutter run` to install the app and test it. Note that you need to test - it on a real device instead of a simulator. Next click on one of the products - in the example App, this enables the "SANDBOX ACCOUNT" section in the iOS - settings. You will now be asked to sign in with your sandbox test account to - complete the purchase (no worries you won't be charged). If for some reason - you aren't asked to sign-in or the wrong user is listed, go into the iOS - settings ("Settings" -> "App Store" -> "SANDBOX ACCOUNT") and update your - sandbox account from there. This procedure is explained in great detail in - the [Testing In-App Purchases with Sandbox](https://developer.apple.com/documentation/storekit/in-app_purchase/testing_in-app_purchases_with_sandbox?language=objc) article. - - -**Important:** signing into any production service (including iTunes!) with the -sandbox test account will permanently invalidate it. From 5252d6e1fe2b290bbfd35554e229b59051e19038 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Tue, 30 Jan 2024 15:00:35 -0500 Subject: [PATCH 17/20] Readme link to signing docs and changelog verbiage update --- .../in_app_purchase/in_app_purchase_android/CHANGELOG.md | 2 +- .../in_app_purchase_android/example/README.md | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) 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 7acf31dc171..72b8bb36ff3 100644 --- a/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.3.0+18 -* Adds country code api for android. +* Adds new getCountryCode() method to InAppPurchaseAndroidPlatformAddition to get a customer's country code. * Updates compileSdk version to 34. ## 0.3.0+17 diff --git a/packages/in_app_purchase/in_app_purchase_android/example/README.md b/packages/in_app_purchase/in_app_purchase_android/example/README.md index ed5b4d6be70..a820209c222 100644 --- a/packages/in_app_purchase/in_app_purchase_android/example/README.md +++ b/packages/in_app_purchase/in_app_purchase_android/example/README.md @@ -45,8 +45,9 @@ we've also included a high level guide below. information. `keystore.example.properties` exists as an example to follow. It's impossible to use any of the `BillingClient` APIs from an unsigned APK. See - [here](https://developer.android.com/studio/publish/app-signing#secure-shared-keystore) - and [here](https://developer.android.com/studio/publish/app-signing#sign-apk) + [keystore](https://developer.android.com/studio/publish/app-signing#secure-shared-keystore) + and [signing](https://developer.android.com/studio/publish/app-signing#sign-apk) and + [flutter-android](https://docs.flutter.dev/deployment/android#signing-the-app) for more information. 6. Build a signed apk. `flutter build apk` will work for this, the gradle files From 5e363fc5c9a0dd818fa155df398a9d12db638d16 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Tue, 30 Jan 2024 15:17:03 -0500 Subject: [PATCH 18/20] Restore getCountryCode tests --- ...rchase_android_platform_addition_test.dart | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) 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 4dd65acea90..2ad4d13de56 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 @@ -7,8 +7,10 @@ import 'package:flutter/widgets.dart' as widgets; 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_android/src/billing_client_wrappers/billing_config_wrapper.dart'; import 'package:in_app_purchase_android/src/channel.dart'; +import 'billing_client_wrappers/billing_client_wrapper_test.dart'; import 'billing_client_wrappers/purchase_wrapper_test.dart'; import 'stub_in_app_purchase_platform.dart'; @@ -61,6 +63,26 @@ void main() { }); }); + group('billingConfig', () { + const String billingConfigMethodName = 'BillingClient#getBillingConfig()'; + test('getCountryCode success', () async { + const String expectedCountryCode = 'US'; + const BillingConfigWrapper expected = BillingConfigWrapper( + countryCode: expectedCountryCode, + responseCode: BillingResponse.ok, + debugMessage: 'dummy message'); + + stubPlatform.addResponse( + name: billingConfigMethodName, + value: buildBillingConfigMap(expected), + ); + final String countryCode = + await iapAndroidPlatformAddition.getCountryCode(); + + expect(countryCode, equals(expectedCountryCode)); + }); + }); + group('queryPastPurchase', () { group('queryPurchaseDetails', () { const String queryMethodName = From 62477c49af2cecee13405658cc8f98102122c426 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Tue, 30 Jan 2024 15:25:09 -0500 Subject: [PATCH 19/20] Use run with client since BillingConfigWrapper uses a billing result --- .../src/in_app_purchase_android_platform_addition.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart index de27cbbc69e..84d01cf15a5 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart @@ -7,6 +7,7 @@ import 'package:in_app_purchase_platform_interface/in_app_purchase_platform_inte import '../billing_client_wrappers.dart'; import '../in_app_purchase_android.dart'; +import 'billing_client_wrappers/billing_config_wrapper.dart'; /// Contains InApp Purchase features that are only available on PlayStore. class InAppPurchaseAndroidPlatformAddition @@ -152,9 +153,9 @@ class InAppPurchaseAndroidPlatformAddition /// See: https://developer.android.com/reference/com/android/billingclient/api/BillingConfig /// See: https://unicode.org/cldr/charts/latest/supplemental/territory_containment_un_m_49.html Future getCountryCode() async { - return _billingClientManager.runWithClientNonRetryable( - (BillingClient client) async => - (await client.getBillingConfig()).countryCode, - ); + + BillingConfigWrapper billingConfig = await _billingClientManager + .runWithClient((BillingClient client) => client.getBillingConfig()); + return billingConfig.countryCode; } } From f047aac4f142313819b9f5182f7a63acaf0d3769 Mon Sep 17 00:00:00 2001 From: Reid Baker Date: Tue, 30 Jan 2024 15:25:09 -0500 Subject: [PATCH 20/20] Use run with client since BillingConfigWrapper uses a billing result --- .../lib/src/in_app_purchase_android_platform_addition.dart | 3 +-- .../test/in_app_purchase_android_platform_addition_test.dart | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart index 84d01cf15a5..aa660192ee3 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform_addition.dart @@ -153,8 +153,7 @@ class InAppPurchaseAndroidPlatformAddition /// See: https://developer.android.com/reference/com/android/billingclient/api/BillingConfig /// See: https://unicode.org/cldr/charts/latest/supplemental/territory_containment_un_m_49.html Future getCountryCode() async { - - BillingConfigWrapper billingConfig = await _billingClientManager + final BillingConfigWrapper billingConfig = await _billingClientManager .runWithClient((BillingClient client) => client.getBillingConfig()); return billingConfig.countryCode; } 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 2ad4d13de56..4a97a43df5e 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 @@ -69,7 +69,7 @@ void main() { const String expectedCountryCode = 'US'; const BillingConfigWrapper expected = BillingConfigWrapper( countryCode: expectedCountryCode, - responseCode: BillingResponse.ok, + responseCode: BillingResponse.ok, debugMessage: 'dummy message'); stubPlatform.addResponse(