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 8d4857a49f8..440c322c4a0 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.6 + +* Introduces new `ReplacementMode` for Android's billing client as `ProrationMode` is being deprecated. + ## 0.3.5+2 * Bumps androidx.annotation:annotation from 1.7.1 to 1.8.0. diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Messages.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Messages.java index 6a465b4bb2c..0602260e72f 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Messages.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Messages.java @@ -1,7 +1,7 @@ // 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. -// Autogenerated from Pigeon (v17.1.2), do not edit directly. +// Autogenerated from Pigeon (v17.3.0), do not edit directly. // See also: https://pub.dev/packages/pigeon package io.flutter.plugins.inapppurchase; @@ -962,6 +962,19 @@ public void setProrationMode(@NonNull Long setterArg) { this.prorationMode = setterArg; } + private @NonNull Long replacementMode; + + public @NonNull Long getReplacementMode() { + return replacementMode; + } + + public void setReplacementMode(@NonNull Long setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"replacementMode\" is null."); + } + this.replacementMode = setterArg; + } + private @Nullable String offerToken; public @Nullable String getOfferToken() { @@ -1033,6 +1046,14 @@ public static final class Builder { return this; } + private @Nullable Long replacementMode; + + @CanIgnoreReturnValue + public @NonNull Builder setReplacementMode(@NonNull Long setterArg) { + this.replacementMode = setterArg; + return this; + } + private @Nullable String offerToken; @CanIgnoreReturnValue @@ -1077,6 +1098,7 @@ public static final class Builder { PlatformBillingFlowParams pigeonReturn = new PlatformBillingFlowParams(); pigeonReturn.setProduct(product); pigeonReturn.setProrationMode(prorationMode); + pigeonReturn.setReplacementMode(replacementMode); pigeonReturn.setOfferToken(offerToken); pigeonReturn.setAccountId(accountId); pigeonReturn.setObfuscatedProfileId(obfuscatedProfileId); @@ -1088,9 +1110,10 @@ public static final class Builder { @NonNull ArrayList toList() { - ArrayList toListResult = new ArrayList(7); + ArrayList toListResult = new ArrayList(8); toListResult.add(product); toListResult.add(prorationMode); + toListResult.add(replacementMode); toListResult.add(offerToken); toListResult.add(accountId); toListResult.add(obfuscatedProfileId); @@ -1110,15 +1133,22 @@ ArrayList toList() { : ((prorationMode instanceof Integer) ? (Integer) prorationMode : (Long) prorationMode)); - Object offerToken = list.get(2); + Object replacementMode = list.get(2); + pigeonResult.setReplacementMode( + (replacementMode == null) + ? null + : ((replacementMode instanceof Integer) + ? (Integer) replacementMode + : (Long) replacementMode)); + Object offerToken = list.get(3); pigeonResult.setOfferToken((String) offerToken); - Object accountId = list.get(3); + Object accountId = list.get(4); pigeonResult.setAccountId((String) accountId); - Object obfuscatedProfileId = list.get(4); + Object obfuscatedProfileId = list.get(5); pigeonResult.setObfuscatedProfileId((String) obfuscatedProfileId); - Object oldProduct = list.get(5); + Object oldProduct = list.get(6); pigeonResult.setOldProduct((String) oldProduct); - Object purchaseToken = list.get(6); + Object purchaseToken = list.get(7); pigeonResult.setPurchaseToken((String) purchaseToken); return pigeonResult; } 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 11ea6da2195..c7305a69938 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 @@ -60,6 +60,11 @@ class MethodCallHandlerImpl implements Application.ActivityLifecycleCallbacks, I com.android.billingclient.api.BillingFlowParams.ProrationMode .UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY; + @VisibleForTesting + static final int REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY = + com.android.billingclient.api.BillingFlowParams.SubscriptionUpdateParams.ReplacementMode + .UNKNOWN_REPLACEMENT_MODE; + private static final String TAG = "InAppPurchasePlugin"; private static final String LOAD_PRODUCT_DOC_URL = "https://github.com/flutter/packages/blob/main/packages/in_app_purchase/in_app_purchase/README.md#loading-products-for-sale"; @@ -285,9 +290,20 @@ public void queryProductDetailsAsync( } } + if (params.getProrationMode() != PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY + && params.getReplacementMode() + != REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY) { + throw new FlutterError( + "IN_APP_PURCHASE_CONFLICT_PRORATION_MODE_REPLACEMENT_MODE", + "launchBillingFlow failed because you provided both prorationMode and replacementMode. You can only provide one of them.", + null); + } + if (params.getOldProduct() == null - && params.getProrationMode() - != PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY) { + && (params.getProrationMode() + != PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY + || params.getReplacementMode() + != REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY)) { throw new FlutterError( "IN_APP_PURCHASE_REQUIRE_OLD_PRODUCT", "launchBillingFlow failed because oldProduct is null. You must provide a valid oldProduct in order to use a proration mode.", @@ -336,9 +352,16 @@ public void queryProductDetailsAsync( && !params.getOldProduct().isEmpty() && params.getPurchaseToken() != null) { subscriptionUpdateParamsBuilder.setOldPurchaseToken(params.getPurchaseToken()); - // Set the prorationMode using a helper to minimize impact of deprecation warning suppression. - setReplaceProrationMode( - subscriptionUpdateParamsBuilder, params.getProrationMode().intValue()); + if (params.getProrationMode() + != PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY) { + setReplaceProrationMode( + subscriptionUpdateParamsBuilder, params.getProrationMode().intValue()); + } + if (params.getReplacementMode() + != REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY) { + subscriptionUpdateParamsBuilder.setSubscriptionReplacementMode( + params.getReplacementMode().intValue()); + } paramsBuilder.setSubscriptionUpdateParams(subscriptionUpdateParamsBuilder.build()); } return fromBillingResult(billingClient.launchBillingFlow(activity, paramsBuilder.build())); @@ -385,7 +408,8 @@ public void queryPurchasesAsync( } try { - // Like in our connect call, consider the billing client responding a "success" here regardless + // Like in our connect call, consider the billing client responding a "success" here + // regardless // of status code. QueryPurchasesParams.Builder paramsBuilder = QueryPurchasesParams.newBuilder(); paramsBuilder.setProductType(toProductTypeString(productType)); 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 ca428910868..58b1c42a0e4 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 @@ -6,6 +6,7 @@ import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.ACTIVITY_UNAVAILABLE; import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY; +import static io.flutter.plugins.inapppurchase.MethodCallHandlerImpl.REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY; import static java.util.Arrays.asList; import static java.util.Collections.singletonList; import static java.util.Collections.unmodifiableList; @@ -556,6 +557,8 @@ public void launchBillingFlow_null_AccountId_do_not_crash() { paramsBuilder.setProduct(productId); paramsBuilder.setProrationMode( (long) PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); + paramsBuilder.setReplacementMode( + (long) REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); // Launch the billing flow BillingResult billingResult = buildBillingResult(); @@ -581,6 +584,8 @@ public void launchBillingFlow_ok_null_OldProduct() { paramsBuilder.setAccountId(accountId); paramsBuilder.setProrationMode( (long) PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); + paramsBuilder.setReplacementMode( + (long) REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); // Launch the billing flow BillingResult billingResult = buildBillingResult(); @@ -610,6 +615,8 @@ public void launchBillingFlow_ok_null_Activity() { paramsBuilder.setAccountId(accountId); paramsBuilder.setProrationMode( (long) PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); + paramsBuilder.setReplacementMode( + (long) REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); // Assert that the synchronous call throws an exception. FlutterError exception = @@ -633,6 +640,8 @@ public void launchBillingFlow_ok_oldProduct() { paramsBuilder.setOldProduct(oldProductId); paramsBuilder.setProrationMode( (long) PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); + paramsBuilder.setReplacementMode( + (long) REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); // Launch the billing flow BillingResult billingResult = buildBillingResult(); @@ -660,6 +669,8 @@ public void launchBillingFlow_ok_AccountId() { paramsBuilder.setAccountId(accountId); paramsBuilder.setProrationMode( (long) PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); + paramsBuilder.setReplacementMode( + (long) REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); // Launch the billing flow BillingResult billingResult = buildBillingResult(); @@ -695,6 +706,8 @@ public void launchBillingFlow_ok_Proration() { paramsBuilder.setOldProduct(oldProductId); paramsBuilder.setPurchaseToken(purchaseToken); paramsBuilder.setProrationMode((long) prorationMode); + paramsBuilder.setReplacementMode( + (long) REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); // Launch the billing flow BillingResult billingResult = buildBillingResult(); @@ -728,6 +741,8 @@ public void launchBillingFlow_ok_Proration_with_null_OldProduct() { paramsBuilder.setAccountId(accountId); paramsBuilder.setOldProduct(null); paramsBuilder.setProrationMode((long) prorationMode); + paramsBuilder.setReplacementMode( + (long) REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); // Launch the billing flow BillingResult billingResult = buildBillingResult(); @@ -744,6 +759,73 @@ public void launchBillingFlow_ok_Proration_with_null_OldProduct() { .contains("launchBillingFlow failed because oldProduct is null")); } + @Test + @SuppressWarnings(value = "deprecation") + public void launchBillingFlow_ok_Replacement_with_null_OldProduct() { + // Fetch the product details first and query the method call + String productId = "foo"; + String accountId = "account"; + String queryOldProductId = "oldFoo"; + int replacementMode = + BillingFlowParams.SubscriptionUpdateParams.ReplacementMode.CHARGE_PRORATED_PRICE; + queryForProducts(unmodifiableList(asList(productId, queryOldProductId))); + PlatformBillingFlowParams.Builder paramsBuilder = new PlatformBillingFlowParams.Builder(); + paramsBuilder.setProduct(productId); + paramsBuilder.setAccountId(accountId); + paramsBuilder.setOldProduct(null); + paramsBuilder.setProrationMode( + (long) PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); + paramsBuilder.setReplacementMode((long) replacementMode); + + // Launch the billing flow + BillingResult billingResult = buildBillingResult(); + when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult); + + // Assert that the synchronous call throws an exception. + FlutterError exception = + assertThrows( + FlutterError.class, + () -> methodChannelHandler.launchBillingFlow(paramsBuilder.build())); + assertEquals("IN_APP_PURCHASE_REQUIRE_OLD_PRODUCT", exception.code); + assertTrue( + Objects.requireNonNull(exception.getMessage()) + .contains("launchBillingFlow failed because oldProduct is null")); + } + + @Test + @SuppressWarnings(value = "deprecation") + public void launchBillingFlow_ok_Proration_and_Replacement_conflict() { + // Fetch the product details first and query the method call + String productId = "foo"; + String accountId = "account"; + String queryOldProductId = "oldFoo"; + int prorationMode = BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_PRORATED_PRICE; + int replacementMode = + BillingFlowParams.SubscriptionUpdateParams.ReplacementMode.CHARGE_PRORATED_PRICE; + queryForProducts(unmodifiableList(asList(productId, queryOldProductId))); + PlatformBillingFlowParams.Builder paramsBuilder = new PlatformBillingFlowParams.Builder(); + paramsBuilder.setProduct(productId); + paramsBuilder.setAccountId(accountId); + paramsBuilder.setOldProduct(queryOldProductId); + paramsBuilder.setProrationMode((long) prorationMode); + paramsBuilder.setReplacementMode((long) replacementMode); + + // Launch the billing flow + BillingResult billingResult = buildBillingResult(); + when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult); + + // Assert that the synchronous call throws an exception. + FlutterError exception = + assertThrows( + FlutterError.class, + () -> methodChannelHandler.launchBillingFlow(paramsBuilder.build())); + assertEquals("IN_APP_PURCHASE_CONFLICT_PRORATION_MODE_REPLACEMENT_MODE", exception.code); + assertTrue( + Objects.requireNonNull(exception.getMessage()) + .contains( + "launchBillingFlow failed because you provided both prorationMode and replacementMode. You can only provide one of them.")); + } + // TODO(gmackall): Replace uses of deprecated ProrationMode enum values with new // ReplacementMode enum values. // https://github.com/flutter/flutter/issues/128957. @@ -763,6 +845,8 @@ public void launchBillingFlow_ok_Full() { paramsBuilder.setOldProduct(oldProductId); paramsBuilder.setPurchaseToken(purchaseToken); paramsBuilder.setProrationMode((long) prorationMode); + paramsBuilder.setReplacementMode( + (long) REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); // Launch the billing flow BillingResult billingResult = buildBillingResult(); @@ -790,6 +874,8 @@ public void launchBillingFlow_clientDisconnected() { paramsBuilder.setAccountId(accountId); paramsBuilder.setProrationMode( (long) PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); + paramsBuilder.setReplacementMode( + (long) REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); // Assert that the synchronous call throws an exception. FlutterError exception = @@ -811,6 +897,8 @@ public void launchBillingFlow_productNotFound() { paramsBuilder.setAccountId(accountId); paramsBuilder.setProrationMode( (long) PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); + paramsBuilder.setReplacementMode( + (long) REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); // Assert that the synchronous call throws an exception. FlutterError exception = @@ -835,6 +923,8 @@ public void launchBillingFlow_oldProductNotFound() { paramsBuilder.setOldProduct(oldProductId); paramsBuilder.setProrationMode( (long) PRORATION_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); + paramsBuilder.setReplacementMode( + (long) REPLACEMENT_MODE_UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY); // Assert that the synchronous call throws an exception. FlutterError exception = 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 b9417c6b25e..3f7bd499bbf 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 @@ -190,7 +190,8 @@ class BillingClient { String? obfuscatedProfileId, String? oldProduct, String? purchaseToken, - ProrationMode? prorationMode}) async { + ProrationMode? prorationMode, + ReplacementMode? replacementMode}) async { assert((oldProduct == null) == (purchaseToken == null), 'oldProduct and purchaseToken must both be set, or both be null.'); return resultWrapperFromPlatform( @@ -198,6 +199,8 @@ class BillingClient { product: product, prorationMode: const ProrationModeConverter().toJson(prorationMode ?? ProrationMode.unknownSubscriptionUpgradeDowngradePolicy), + replacementMode: const ReplacementModeConverter() + .toJson(replacementMode ?? ReplacementMode.unknownReplacementMode), offerToken: offerToken, accountId: accountId, obfuscatedProfileId: obfuscatedProfileId, @@ -622,6 +625,76 @@ class ProrationModeConverter implements JsonConverter { int toJson(ProrationMode object) => _$ProrationModeEnumMap[object]!; } +/// Enum representing the replacement mode. +/// +/// When upgrading or downgrading a subscription, set this mode to provide details +/// about the replacement that will be applied when the subscription changes. +/// +/// Wraps [`BillingFlowParams.SubscriptionUpdateParams.ReplacementMode`](https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.SubscriptionUpdateParams.ReplacementMode) +/// See the linked documentation for an explanation of the different constants. +@JsonEnum(alwaysCreate: true) +enum ReplacementMode { +// WARNING: Changes to this class need to be reflected in our generated code. +// Run `flutter packages pub run build_runner watch` to rebuild and watch for +// further changes. + + /// Unknown upgrade or downgrade policy. + @JsonValue(0) + unknownReplacementMode, + + /// Replacement takes effect immediately, and the remaining time will be prorated + /// and credited to the user. + /// + /// This is the current default behavior. + @JsonValue(1) + withTimeProration, + + /// Replacement takes effect immediately, and the billing cycle remains the same. + /// + /// The price for the remaining period will be charged. + /// This option is only available for subscription upgrade. + @JsonValue(2) + chargeProratedPrice, + + /// Replacement takes effect immediately, and the new price will be charged on next + /// recurrence time. + /// + /// The billing cycle stays the same. + @JsonValue(3) + withoutProration, + + /// Replacement takes effect when the old plan expires, and the new price will + /// be charged at the same time. + @JsonValue(6) + deferred, + + /// Replacement takes effect immediately, and the user is charged full price + /// of new plan and is given a full billing cycle of subscription, plus + /// remaining prorated time from the old plan. + @JsonValue(5) + chargeFullPrice, +} + +/// Serializer for [ReplacementMode]. +/// +/// Use these in `@JsonSerializable()` classes by annotating them with +/// `@ReplacementModeConverter()`. +class ReplacementModeConverter implements JsonConverter { + /// Default const constructor. + const ReplacementModeConverter(); + + @override + ReplacementMode fromJson(int? json) { + if (json == null) { + return ReplacementMode.unknownReplacementMode; + } + return $enumDecode(_$ReplacementModeEnumMap, json); + } + + @override + int toJson(ReplacementMode object) => _$ReplacementModeEnumMap[object]!; +} + /// Features/capabilities supported by [BillingClient.isFeatureSupported()](https://developer.android.com/reference/com/android/billingclient/api/BillingClient.FeatureType). @JsonEnum(alwaysCreate: true) enum BillingClientFeature { diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.g.dart index 0768c35deec..eb0033193d9 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.g.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/billing_client_wrapper.g.dart @@ -42,6 +42,15 @@ const _$ProrationModeEnumMap = { ProrationMode.immediateAndChargeFullPrice: 5, }; +const _$ReplacementModeEnumMap = { + ReplacementMode.unknownReplacementMode: 0, + ReplacementMode.withTimeProration: 1, + ReplacementMode.chargeProratedPrice: 2, + ReplacementMode.withoutProration: 3, + ReplacementMode.deferred: 6, + ReplacementMode.chargeFullPrice: 5, +}; + const _$BillingClientFeatureEnumMap = { BillingClientFeature.inAppItemsOnVR: 'inAppItemsOnVr', BillingClientFeature.priceChangeConfirmation: 'priceChangeConfirmation', diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart index afa6932776b..333ccc83bc2 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart @@ -162,7 +162,8 @@ class InAppPurchaseAndroidPlatform extends InAppPurchasePlatform { oldProduct: changeSubscriptionParam?.oldPurchaseDetails.productID, purchaseToken: changeSubscriptionParam ?.oldPurchaseDetails.verificationData.serverVerificationData, - prorationMode: changeSubscriptionParam?.prorationMode), + prorationMode: changeSubscriptionParam?.prorationMode, + replacementMode: changeSubscriptionParam?.replacementMode), ); return billingResultWrapper.responseCode == BillingResponse.ok; } diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/messages.g.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/messages.g.dart index 1b5753f8006..e6444b8d9b6 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/messages.g.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/messages.g.dart @@ -1,7 +1,7 @@ // 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. -// Autogenerated from Pigeon (v17.1.2), do not edit directly. +// Autogenerated from Pigeon (v17.3.0), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers @@ -324,6 +324,7 @@ class PlatformBillingFlowParams { PlatformBillingFlowParams({ required this.product, required this.prorationMode, + required this.replacementMode, this.offerToken, this.accountId, this.obfuscatedProfileId, @@ -335,6 +336,8 @@ class PlatformBillingFlowParams { int prorationMode; + int replacementMode; + String? offerToken; String? accountId; @@ -349,6 +352,7 @@ class PlatformBillingFlowParams { return [ product, prorationMode, + replacementMode, offerToken, accountId, obfuscatedProfileId, @@ -362,11 +366,12 @@ class PlatformBillingFlowParams { return PlatformBillingFlowParams( product: result[0]! as String, prorationMode: result[1]! as int, - offerToken: result[2] as String?, - accountId: result[3] as String?, - obfuscatedProfileId: result[4] as String?, - oldProduct: result[5] as String?, - purchaseToken: result[6] as String?, + replacementMode: result[2]! as int, + offerToken: result[3] as String?, + accountId: result[4] as String?, + obfuscatedProfileId: result[5] as String?, + oldProduct: result[6] as String?, + purchaseToken: result[7] as String?, ); } } diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/types/change_subscription_param.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/types/change_subscription_param.dart index 1099da3bf15..f76fc3e9005 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/types/change_subscription_param.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/types/change_subscription_param.dart @@ -10,7 +10,8 @@ class ChangeSubscriptionParam { /// Creates a new change subscription param object with given data ChangeSubscriptionParam({ required this.oldPurchaseDetails, - this.prorationMode, + @Deprecated('Use replacementMode instead') this.prorationMode, + this.replacementMode, }); /// The purchase object of the existing subscription that the user needs to @@ -21,5 +22,12 @@ class ChangeSubscriptionParam { /// /// This is an optional parameter that indicates how to handle the existing /// subscription when the new subscription comes into effect. + @Deprecated('Use replacementMode instead') final ProrationMode? prorationMode; + + /// The replacement mode. + /// + /// This is an optional parameter that indicates how to handle the existing + /// subscription when the new subscription comes into effect. + final ReplacementMode? replacementMode; } diff --git a/packages/in_app_purchase/in_app_purchase_android/pigeons/messages.dart b/packages/in_app_purchase/in_app_purchase_android/pigeons/messages.dart index 2921c0907ca..d0bbc51e973 100644 --- a/packages/in_app_purchase/in_app_purchase_android/pigeons/messages.dart +++ b/packages/in_app_purchase/in_app_purchase_android/pigeons/messages.dart @@ -118,6 +118,7 @@ class PlatformBillingFlowParams { PlatformBillingFlowParams({ required this.product, required this.prorationMode, + required this.replacementMode, required this.offerToken, required this.accountId, required this.obfuscatedProfileId, @@ -130,6 +131,7 @@ class PlatformBillingFlowParams { // to constants on the Java side, but it's deprecated anyway so that will be // resolved during the update to the new API. final int prorationMode; + final int replacementMode; final String? offerToken; final String? accountId; final String? obfuscatedProfileId; 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 e2047d02ba8..d12eeeb7baf 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.5+2 +version: 0.3.6 environment: sdk: ^3.2.0