From c6a5001e730a53dbb73702147e7248a531256da5 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Tue, 26 Apr 2022 16:46:56 -0700 Subject: [PATCH 01/22] in_app_purchase: Upgrade build.gradle dependencies --- .../in_app_purchase_android/android/build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 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 9a5a74d0032b..439e7bd88f3c 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 @@ -52,11 +52,11 @@ android { } dependencies { - implementation 'androidx.annotation:annotation:1.0.0' - implementation 'com.android.billingclient:billing:3.0.2' + implementation 'androidx.annotation:annotation:1.3.0' + implementation 'com.android.billingclient:billing:5.0.0' testImplementation 'junit:junit:4.13.2' - testImplementation 'org.json:json:20180813' + testImplementation 'org.json:json:20220320' testImplementation 'org.mockito:mockito-core:3.6.0' - androidTestImplementation 'androidx.test:runner:1.1.1' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' + androidTestImplementation 'androidx.test:runner:1.4.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' } From f0e9cebdcb2dddc26ff5baf8643d751fd5bbf205 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Tue, 26 Apr 2022 16:49:20 -0700 Subject: [PATCH 02/22] upgrade mockito --- .../in_app_purchase_android/android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 439e7bd88f3c..663a4dfad46e 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 @@ -56,7 +56,7 @@ dependencies { implementation 'com.android.billingclient:billing:5.0.0' testImplementation 'junit:junit:4.13.2' testImplementation 'org.json:json:20220320' - testImplementation 'org.mockito:mockito-core:3.6.0' + testImplementation 'org.mockito:mockito-core:4.5.1' androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' } From 6cb46b1a3234d42683311e7566747b6f81df7fd8 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Tue, 26 Apr 2022 17:25:15 -0700 Subject: [PATCH 03/22] Support async queryPurchasesAsync() --- .../inapppurchase/MethodCallHandlerImpl.java | 16 +++++++- .../inapppurchase/MethodCallHandlerTest.java | 41 +++++++++++++++++++ 2 files changed, 55 insertions(+), 2 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 adad84b39e1d..0bc60aa1aae8 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 @@ -286,14 +286,26 @@ public void onConsumeResponse(BillingResult billingResult, String outToken) { billingClient.consumeAsync(params, listener); } - private void queryPurchases(String skuType, MethodChannel.Result result) { + private void queryPurchasesAsync(String skuType, MethodChannel.Result result) { if (billingClientError(result)) { return; } // Like in our connect call, consider the billing client responding a "success" here regardless // of status code. - result.success(fromPurchasesResult(billingClient.queryPurchases(skuType))); + billingClient.queryPurchaseHistoryAsync( + skuType, + new PurchasesResponseListener() { + @Override + public void onQueryPurchasesResponse( + BillingResult billingResult, List purchasesList) { + final Map serialized = new HashMap<>(); + serialized.put("billingResult", Translator.fromBillingResult(billingResult)); + serialized.put( + "purchaseList", fromPurchaseList(purchasesList)); + result.success(serialized); + } + }); } private void queryPurchaseHistoryAsync(String skuType, final MethodChannel.Result result) { 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 d676bf3436ee..644b7fc8fc36 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 @@ -495,6 +495,47 @@ public void launchBillingFlow_ok_Proration_with_null_OldSku() { verify(result, never()).success(any()); } + @Test + public void launchBillingFlow_ok_Full() { + // Fetch the sku details first and query the method call + String skuId = "foo"; + String oldSkuId = "oldFoo"; + String purchaseToken = "purchaseTokenFoo"; + String accountId = "account"; + int prorationMode = BillingFlowParams.ProrationMode.IMMEDIATE_AND_CHARGE_FULL_PRICE; + queryForSkus(unmodifiableList(asList(skuId, oldSkuId))); + HashMap arguments = new HashMap<>(); + arguments.put("sku", skuId); + arguments.put("accountId", accountId); + arguments.put("oldSku", oldSkuId); + arguments.put("purchaseToken", purchaseToken); + arguments.put("prorationMode", prorationMode); + MethodCall launchCall = new MethodCall(LAUNCH_BILLING_FLOW, arguments); + + // Launch the billing flow + BillingResult billingResult = + BillingResult.newBuilder() + .setResponseCode(100) + .setDebugMessage("dummy debug message") + .build(); + when(mockBillingClient.launchBillingFlow(any(), any())).thenReturn(billingResult); + methodChannelHandler.onMethodCall(launchCall, result); + + // Verify we pass the arguments to the billing flow + ArgumentCaptor billingFlowParamsCaptor = + ArgumentCaptor.forClass(BillingFlowParams.class); + verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); + BillingFlowParams params = billingFlowParamsCaptor.getValue(); + assertEquals(params.getSku(), skuId); + assertEquals(params.getOldSku(), oldSkuId); + assertEquals(params.getOldSkuPurchaseToken(), purchaseToken); + assertEquals(params.getReplaceSkusProrationMode(), prorationMode); + + // Verify we pass the response code to result + verify(result, never()).error(any(), any(), any()); + verify(result, times(1)).success(fromBillingResult(billingResult)); + } + @Test public void launchBillingFlow_clientDisconnected() { // Prepare the launch call after disconnecting the client From 04fc57b1a12d7f45944e6c742f88c4b23cb6f158 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Wed, 27 Apr 2022 11:05:43 -0700 Subject: [PATCH 04/22] Add new API --- .../inapppurchase/InAppPurchasePlugin.java | 4 ++- .../inapppurchase/MethodCallHandlerImpl.java | 25 ++++++++++++++++--- .../plugins/inapppurchase/Translator.java | 6 +++-- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java index b21ab6992608..1ffac27b6d1c 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java @@ -38,7 +38,8 @@ static final class MethodNames { "BillingClient#launchBillingFlow(Activity, BillingFlowParams)"; static final String ON_PURCHASES_UPDATED = "PurchasesUpdatedListener#onPurchasesUpdated(int, List)"; - static final String QUERY_PURCHASES = "BillingClient#queryPurchases(String)"; + static final String QUERY_PURCHASES = "BillingClient#queryPurchasesAsync(String)"; + static final String QUERY_PURCHASES_ASYNC = "BillingClient#queryPurchasesAsync(String)"; static final String QUERY_PURCHASE_HISTORY_ASYNC = "BillingClient#queryPurchaseHistoryAsync(String, PurchaseHistoryResponseListener)"; static final String CONSUME_PURCHASE_ASYNC = @@ -48,6 +49,7 @@ static final class MethodNames { static final String IS_FEATURE_SUPPORTED = "BillingClient#isFeatureSupported(String)"; static final String LAUNCH_PRICE_CHANGE_CONFIRMATION_FLOW = "BillingClient#launchPriceChangeConfirmationFlow (Activity, PriceChangeFlowParams, PriceChangeConfirmationListener)"; + static final String GET_CONNECTION_STATE = "BillingClient#getConnectionState()"; private MethodNames() {}; } 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 0bc60aa1aae8..5e1694d939e7 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 @@ -131,8 +131,11 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { : ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY, result); break; - case InAppPurchasePlugin.MethodNames.QUERY_PURCHASES: - queryPurchases((String) call.argument("skuType"), result); + case InAppPurchasePlugin.MethodNames.QUERY_PURCHASES: // Legacy method name. + queryPurchasesAsync((String) call.argument("skuType"), result); + break; + case InAppPurchasePlugin.MethodNames.QUERY_PURCHASES_ASYNC: + queryPurchasesAsync((String) call.argument("skuType"), result); break; case InAppPurchasePlugin.MethodNames.QUERY_PURCHASE_HISTORY_ASYNC: queryPurchaseHistoryAsync((String) call.argument("skuType"), result); @@ -149,6 +152,9 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { case InAppPurchasePlugin.MethodNames.LAUNCH_PRICE_CHANGE_CONFIRMATION_FLOW: launchPriceChangeConfirmationFlow((String) call.argument("sku"), result); break; + case InAppPurchasePlugin.MethodNames.GET_CONNECTION_STATE: + getConnectionState(); + break; default: result.notImplemented(); } @@ -256,7 +262,11 @@ private void launchBillingFlow( paramsBuilder.setObfuscatedProfileId(obfuscatedProfileId); } if (oldSku != null && !oldSku.isEmpty()) { - paramsBuilder.setOldSku(oldSku, purchaseToken); + BillingFlowParams.SubscriptionUpdateParams.Builder subscriptionUpdateParamsBuilder = + BillingFlowParams.SubscriptionUpdateParams.Builder.newBuilder(); + subscriptionUpdateParamsBuilder.setOldSkuPurchaseToken(purchaseToken); + // paramsBuilder.setOldSku(oldSku, purchaseToken); + paramsBuilder.setSubscriptionUpdateParams(subscriptionUpdateParamsBuilder.build()); } // The proration mode value has to match one of the following declared in // https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode @@ -328,6 +338,15 @@ public void onPurchaseHistoryResponse( }); } + private void getConnectionState() { + if (billingClientError(result)) { + return; + } + final Map serialized = new HashMap<>(); + serialized.put("connectionState", billingClient.getConnectionState()); + result.success(serialized); + } + private void startConnection(final int handle, final MethodChannel.Result result) { if (billingClient == null) { billingClient = billingClientFactory.createBillingClient(applicationContext, methodChannel); 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 7546fe7db58d..0ea875259566 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 @@ -61,12 +61,13 @@ static HashMap fromPurchase(Purchase purchase) { info.put("purchaseTime", purchase.getPurchaseTime()); info.put("purchaseToken", purchase.getPurchaseToken()); info.put("signature", purchase.getSignature()); - info.put("sku", purchase.getSku()); + info.put("sku", purchase.getSkus()); info.put("isAutoRenewing", purchase.isAutoRenewing()); info.put("originalJson", purchase.getOriginalJson()); info.put("developerPayload", purchase.getDeveloperPayload()); info.put("isAcknowledged", purchase.isAcknowledged()); info.put("purchaseState", purchase.getPurchaseState()); + info.put("quantity", purchase.getQuantity()); AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers(); if (accountIdentifiers != null) { info.put("obfuscatedAccountId", accountIdentifiers.getObfuscatedAccountId()); @@ -81,9 +82,10 @@ static HashMap fromPurchaseHistoryRecord( info.put("purchaseTime", purchaseHistoryRecord.getPurchaseTime()); info.put("purchaseToken", purchaseHistoryRecord.getPurchaseToken()); info.put("signature", purchaseHistoryRecord.getSignature()); - info.put("sku", purchaseHistoryRecord.getSku()); + info.put("sku", purchaseHistoryRecord.getSkus()); info.put("developerPayload", purchaseHistoryRecord.getDeveloperPayload()); info.put("originalJson", purchaseHistoryRecord.getOriginalJson()); + info.put("quantity", purchaseHistoryRecord.getQuantity()); return info; } From 32ee0b11491effd1bb5974057b318fc3eec97596 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Wed, 27 Apr 2022 12:31:15 -0700 Subject: [PATCH 05/22] Use setSubscriptionUpdateParams --- .../plugins/inapppurchase/MethodCallHandlerImpl.java | 9 ++++----- .../io/flutter/plugins/inapppurchase/Translator.java | 12 ++++++++++-- 2 files changed, 14 insertions(+), 7 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 5e1694d939e7..e2e41bafe005 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 @@ -255,6 +255,8 @@ private void launchBillingFlow( BillingFlowParams.Builder paramsBuilder = BillingFlowParams.newBuilder().setSkuDetails(skuDetails); + BillingFlowParams.SubscriptionUpdateParams.Builder subscriptionUpdateParamsBuilder = + BillingFlowParams.SubscriptionUpdateParams.Builder.newBuilder(); if (accountId != null && !accountId.isEmpty()) { paramsBuilder.setObfuscatedAccountId(accountId); } @@ -262,15 +264,12 @@ private void launchBillingFlow( paramsBuilder.setObfuscatedProfileId(obfuscatedProfileId); } if (oldSku != null && !oldSku.isEmpty()) { - BillingFlowParams.SubscriptionUpdateParams.Builder subscriptionUpdateParamsBuilder = - BillingFlowParams.SubscriptionUpdateParams.Builder.newBuilder(); subscriptionUpdateParamsBuilder.setOldSkuPurchaseToken(purchaseToken); - // paramsBuilder.setOldSku(oldSku, purchaseToken); - paramsBuilder.setSubscriptionUpdateParams(subscriptionUpdateParamsBuilder.build()); } // The proration mode value has to match one of the following declared in // https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode - paramsBuilder.setReplaceSkusProrationMode(prorationMode); + subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(prorationMode); + paramsBuilder.setSubscriptionUpdateParams(subscriptionUpdateParamsBuilder.build()); result.success( Translator.fromBillingResult( billingClient.launchBillingFlow(activity, paramsBuilder.build()))); 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 0ea875259566..d8744e12150c 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 @@ -56,12 +56,16 @@ static List> fromSkuDetailsList( static HashMap fromPurchase(Purchase purchase) { HashMap info = new HashMap<>(); + List skus = purchase.getSkus(); info.put("orderId", purchase.getOrderId()); info.put("packageName", purchase.getPackageName()); info.put("purchaseTime", purchase.getPurchaseTime()); info.put("purchaseToken", purchase.getPurchaseToken()); info.put("signature", purchase.getSignature()); - info.put("sku", purchase.getSkus()); + if (!skus.isEmpty()) { + info.put("sku", skus[0]); + } + info.put("skus", skus); info.put("isAutoRenewing", purchase.isAutoRenewing()); info.put("originalJson", purchase.getOriginalJson()); info.put("developerPayload", purchase.getDeveloperPayload()); @@ -79,10 +83,14 @@ static HashMap fromPurchase(Purchase purchase) { static HashMap fromPurchaseHistoryRecord( PurchaseHistoryRecord purchaseHistoryRecord) { HashMap info = new HashMap<>(); + List skus = purchaseHistoryRecord.getSkus(); info.put("purchaseTime", purchaseHistoryRecord.getPurchaseTime()); info.put("purchaseToken", purchaseHistoryRecord.getPurchaseToken()); info.put("signature", purchaseHistoryRecord.getSignature()); - info.put("sku", purchaseHistoryRecord.getSkus()); + if (!skus.isEmpty()) { + info.put("sku", skus[0]); + } + info.put("skus", skus); info.put("developerPayload", purchaseHistoryRecord.getDeveloperPayload()); info.put("originalJson", purchaseHistoryRecord.getOriginalJson()); info.put("quantity", purchaseHistoryRecord.getQuantity()); From f84fdd48df340befff739c7c2e63389274e543fa Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Tue, 3 May 2022 11:18:29 -0700 Subject: [PATCH 06/22] Stuff --- .../io/flutter/plugins/inapppurchase/InAppPurchasePlugin.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/InAppPurchasePlugin.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java index 1ffac27b6d1c..6f4e4bbfd8ee 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java @@ -38,7 +38,7 @@ static final class MethodNames { "BillingClient#launchBillingFlow(Activity, BillingFlowParams)"; static final String ON_PURCHASES_UPDATED = "PurchasesUpdatedListener#onPurchasesUpdated(int, List)"; - static final String QUERY_PURCHASES = "BillingClient#queryPurchasesAsync(String)"; + static final String QUERY_PURCHASES = "BillingClient#queryPurchases(String)"; static final String QUERY_PURCHASES_ASYNC = "BillingClient#queryPurchasesAsync(String)"; static final String QUERY_PURCHASE_HISTORY_ASYNC = "BillingClient#queryPurchaseHistoryAsync(String, PurchaseHistoryResponseListener)"; From cb8b0d3b8ca6fe7423540149b8a6665ad66bf5ca Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Thu, 12 May 2022 01:12:56 -0700 Subject: [PATCH 07/22] Pass OK responseId to flutter --- .../io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java | 2 ++ 1 file changed, 2 insertions(+) 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 e2e41bafe005..99dc6d3b6f90 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 @@ -329,6 +329,8 @@ private void queryPurchaseHistoryAsync(String skuType, final MethodChannel.Resul public void onPurchaseHistoryResponse( BillingResult billingResult, List purchasesList) { final Map serialized = new HashMap<>(); + // The response code is no longer passed, as part of billing 4.1.0, so we pass OK here. + serialized.put("responseCode", BillingClient.BillingResponseCode.OK); serialized.put("billingResult", Translator.fromBillingResult(billingResult)); serialized.put( "purchaseHistoryRecordList", fromPurchaseHistoryRecordList(purchasesList)); From 6823a7de0d6475fe2d6b20166155cf6b9e2914e4 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Mon, 23 May 2022 14:34:21 -0700 Subject: [PATCH 08/22] COmpiling --- .../inapppurchase/MethodCallHandlerImpl.java | 39 +++++++++++-------- .../plugins/inapppurchase/Translator.java | 13 +------ .../example/android/app/build.gradle | 4 +- 3 files changed, 26 insertions(+), 30 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 99dc6d3b6f90..7bb89d57d60d 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 @@ -5,7 +5,7 @@ package io.flutter.plugins.inapppurchase; import static io.flutter.plugins.inapppurchase.Translator.fromPurchaseHistoryRecordList; -import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesResult; +import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesList; import static io.flutter.plugins.inapppurchase.Translator.fromSkuDetailsList; import android.app.Activity; @@ -25,11 +25,14 @@ import com.android.billingclient.api.ConsumeParams; import com.android.billingclient.api.ConsumeResponseListener; import com.android.billingclient.api.PriceChangeFlowParams; +import com.android.billingclient.api.Purchase; import com.android.billingclient.api.PurchaseHistoryRecord; import com.android.billingclient.api.PurchaseHistoryResponseListener; +import com.android.billingclient.api.PurchasesResponseListener; import com.android.billingclient.api.SkuDetails; import com.android.billingclient.api.SkuDetailsParams; import com.android.billingclient.api.SkuDetailsResponseListener; +import com.android.billingclient.api.QueryPurchasesParams; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import java.util.HashMap; @@ -153,7 +156,7 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { launchPriceChangeConfirmationFlow((String) call.argument("sku"), result); break; case InAppPurchasePlugin.MethodNames.GET_CONNECTION_STATE: - getConnectionState(); + getConnectionState(result); break; default: result.notImplemented(); @@ -256,7 +259,7 @@ private void launchBillingFlow( BillingFlowParams.Builder paramsBuilder = BillingFlowParams.newBuilder().setSkuDetails(skuDetails); BillingFlowParams.SubscriptionUpdateParams.Builder subscriptionUpdateParamsBuilder = - BillingFlowParams.SubscriptionUpdateParams.Builder.newBuilder(); + BillingFlowParams.SubscriptionUpdateParams.newBuilder(); if (accountId != null && !accountId.isEmpty()) { paramsBuilder.setObfuscatedAccountId(accountId); } @@ -302,18 +305,22 @@ private void queryPurchasesAsync(String skuType, MethodChannel.Result result) { // Like in our connect call, consider the billing client responding a "success" here regardless // of status code. - billingClient.queryPurchaseHistoryAsync( - skuType, + QueryPurchasesParams.Builder paramsBuilder = QueryPurchasesParams.newBuilder(); + paramsBuilder.setProductType(skuType); + billingClient.queryPurchasesAsync( + paramsBuilder.build(), new PurchasesResponseListener() { - @Override - public void onQueryPurchasesResponse( - BillingResult billingResult, List purchasesList) { - final Map serialized = new HashMap<>(); - serialized.put("billingResult", Translator.fromBillingResult(billingResult)); - serialized.put( - "purchaseList", fromPurchaseList(purchasesList)); - result.success(serialized); - } + @Override + public void onQueryPurchasesResponse( + BillingResult billingResult, List purchasesList) { + final Map serialized = new HashMap<>(); + // The response code is no longer passed, as part of billing 4.1.0, so we pass OK here. + serialized.put("responseCode", BillingClient.BillingResponseCode.OK); + serialized.put("billingResult", Translator.fromBillingResult(billingResult)); + serialized.put( + "purchaseList", fromPurchasesList(purchasesList)); + result.success(serialized); + } }); } @@ -329,8 +336,6 @@ private void queryPurchaseHistoryAsync(String skuType, final MethodChannel.Resul public void onPurchaseHistoryResponse( BillingResult billingResult, List purchasesList) { final Map serialized = new HashMap<>(); - // The response code is no longer passed, as part of billing 4.1.0, so we pass OK here. - serialized.put("responseCode", BillingClient.BillingResponseCode.OK); serialized.put("billingResult", Translator.fromBillingResult(billingResult)); serialized.put( "purchaseHistoryRecordList", fromPurchaseHistoryRecordList(purchasesList)); @@ -339,7 +344,7 @@ public void onPurchaseHistoryResponse( }); } - private void getConnectionState() { + private void getConnectionState(final MethodChannel.Result result) { if (billingClientError(result)) { return; } 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 d8744e12150c..8b4bdb754fc1 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 @@ -8,7 +8,6 @@ import com.android.billingclient.api.AccountIdentifiers; import com.android.billingclient.api.BillingResult; import com.android.billingclient.api.Purchase; -import com.android.billingclient.api.Purchase.PurchasesResult; import com.android.billingclient.api.PurchaseHistoryRecord; import com.android.billingclient.api.SkuDetails; import java.util.ArrayList; @@ -63,7 +62,7 @@ static HashMap fromPurchase(Purchase purchase) { info.put("purchaseToken", purchase.getPurchaseToken()); info.put("signature", purchase.getSignature()); if (!skus.isEmpty()) { - info.put("sku", skus[0]); + info.put("sku", skus.get(0)); } info.put("skus", skus); info.put("isAutoRenewing", purchase.isAutoRenewing()); @@ -88,7 +87,7 @@ static HashMap fromPurchaseHistoryRecord( info.put("purchaseToken", purchaseHistoryRecord.getPurchaseToken()); info.put("signature", purchaseHistoryRecord.getSignature()); if (!skus.isEmpty()) { - info.put("sku", skus[0]); + info.put("sku", skus.get(0)); } info.put("skus", skus); info.put("developerPayload", purchaseHistoryRecord.getDeveloperPayload()); @@ -122,14 +121,6 @@ static List> fromPurchaseHistoryRecordList( return serialized; } - static HashMap fromPurchasesResult(PurchasesResult purchasesResult) { - HashMap info = new HashMap<>(); - info.put("responseCode", purchasesResult.getResponseCode()); - info.put("billingResult", fromBillingResult(purchasesResult.getBillingResult())); - info.put("purchasesList", fromPurchasesList(purchasesResult.getPurchasesList())); - return info; - } - static HashMap fromBillingResult(BillingResult billingResult) { HashMap info = new HashMap<>(); info.put("responseCode", billingResult.getResponseCode()); diff --git a/packages/in_app_purchase/in_app_purchase_android/example/android/app/build.gradle b/packages/in_app_purchase/in_app_purchase_android/example/android/app/build.gradle index b7dc1856204e..498355af5976 100644 --- a/packages/in_app_purchase/in_app_purchase_android/example/android/app/build.gradle +++ b/packages/in_app_purchase/in_app_purchase_android/example/android/app/build.gradle @@ -72,7 +72,7 @@ android { defaultConfig { applicationId project.APP_ID minSdkVersion 16 - targetSdkVersion 29 + targetSdkVersion 30 versionCode project.VERSION_CODE versionName project.VERSION_NAME testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" @@ -106,7 +106,7 @@ flutter { } dependencies { - implementation 'com.android.billingclient:billing:3.0.2' + implementation 'com.android.billingclient:billing:5.0.0' testImplementation 'junit:junit:4.13.2' testImplementation 'org.mockito:mockito-core:3.6.0' testImplementation 'org.json:json:20180813' From 3af6514f9790d06f8503c2b5ca2ce61a6532e5d0 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Thu, 2 Jun 2022 15:05:36 -0700 Subject: [PATCH 09/22] Only build SubscriptionUpdateParams when oldsku is passed --- .../plugins/inapppurchase/MethodCallHandlerImpl.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 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 7bb89d57d60d..41bcd6cb50e5 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 @@ -258,8 +258,6 @@ private void launchBillingFlow( BillingFlowParams.Builder paramsBuilder = BillingFlowParams.newBuilder().setSkuDetails(skuDetails); - BillingFlowParams.SubscriptionUpdateParams.Builder subscriptionUpdateParamsBuilder = - BillingFlowParams.SubscriptionUpdateParams.newBuilder(); if (accountId != null && !accountId.isEmpty()) { paramsBuilder.setObfuscatedAccountId(accountId); } @@ -267,12 +265,14 @@ private void launchBillingFlow( paramsBuilder.setObfuscatedProfileId(obfuscatedProfileId); } if (oldSku != null && !oldSku.isEmpty()) { + BillingFlowParams.SubscriptionUpdateParams.Builder subscriptionUpdateParamsBuilder = + BillingFlowParams.SubscriptionUpdateParams.newBuilder(); subscriptionUpdateParamsBuilder.setOldSkuPurchaseToken(purchaseToken); + // The proration mode value has to match one of the following declared in + // https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode + subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(prorationMode); + paramsBuilder.setSubscriptionUpdateParams(subscriptionUpdateParamsBuilder.build()); } - // The proration mode value has to match one of the following declared in - // https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode - subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(prorationMode); - paramsBuilder.setSubscriptionUpdateParams(subscriptionUpdateParamsBuilder.build()); result.success( Translator.fromBillingResult( billingClient.launchBillingFlow(activity, paramsBuilder.build()))); From 847b1dcd4a5350d5f69b6b22ca3a96aaed2ed365 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Thu, 9 Jun 2022 10:55:53 -0700 Subject: [PATCH 10/22] Docs and comments --- .../plugins/inapppurchase/MethodCallHandlerImpl.java | 3 ++- .../java/io/flutter/plugins/inapppurchase/Translator.java | 8 ++++++++ 2 files changed, 10 insertions(+), 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 41bcd6cb50e5..8e65c9cd70d9 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 @@ -314,7 +314,8 @@ private void queryPurchasesAsync(String skuType, MethodChannel.Result result) { public void onQueryPurchasesResponse( BillingResult billingResult, List purchasesList) { final Map serialized = new HashMap<>(); - // The response code is no longer passed, as part of billing 4.1.0, so we pass OK here. + // The response code is no longer passed, as part of billing 4.0, so we pass OK here + // as success is implied by calling this callback. serialized.put("responseCode", BillingClient.BillingResponseCode.OK); serialized.put("billingResult", Translator.fromBillingResult(billingResult)); serialized.put( 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 8b4bdb754fc1..a2da36be9228 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 @@ -61,6 +61,10 @@ static HashMap fromPurchase(Purchase purchase) { info.put("purchaseTime", purchase.getPurchaseTime()); info.put("purchaseToken", purchase.getPurchaseToken()); info.put("signature", purchase.getSignature()); + // TODO(garyq): Remove deprecated `sku`. + // `sku` was deprecated in billion 4.0, but we cannot directly remove it from our + // API instantly. Thus, for backwards compatibility, we pass the first sku here + // and include the rest of the list under `skus`. if (!skus.isEmpty()) { info.put("sku", skus.get(0)); } @@ -86,6 +90,10 @@ static HashMap fromPurchaseHistoryRecord( info.put("purchaseTime", purchaseHistoryRecord.getPurchaseTime()); info.put("purchaseToken", purchaseHistoryRecord.getPurchaseToken()); info.put("signature", purchaseHistoryRecord.getSignature()); + // TODO(garyq): Remove deprecated `sku`. + // `sku` was deprecated in billion 4.0, but we cannot directly remove it from our + // API instantly. Thus, for backwards compatibility, we pass the first sku here + // and include the rest of the list under `skus`. if (!skus.isEmpty()) { info.put("sku", skus.get(0)); } From f679fcd5c8cbe9f202576711c9487d343cbecae7 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Thu, 9 Jun 2022 11:26:16 -0700 Subject: [PATCH 11/22] Adapt dart API --- .../purchase_wrapper.dart | 18 ++++++++++++++++-- .../purchase_wrapper.g.dart | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart index efaf07984df7..52ff42b5a2ff 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart @@ -33,7 +33,8 @@ class PurchaseWrapper { required this.purchaseTime, required this.purchaseToken, required this.signature, - required this.sku, + this.sku = '', // Deprecated + required this.skus, required this.isAutoRenewing, required this.originalJson, this.developerPayload, @@ -104,9 +105,15 @@ class PurchaseWrapper { final String signature; /// The product ID of this purchase. + /// + /// This property is deprecated. Use `skus` instead. @JsonKey(defaultValue: '') final String sku; + /// The product IDs of this purchase. + @JsonKey(defaultValue: []) + final List skus; + /// True for subscriptions that renew automatically. Does not apply to /// [SkuType.inapp] products. /// @@ -178,7 +185,8 @@ class PurchaseHistoryRecordWrapper { required this.purchaseTime, required this.purchaseToken, required this.signature, - required this.sku, + this.sku = '', // Deprecated + required this.skus, required this.originalJson, required this.developerPayload, }); @@ -201,9 +209,15 @@ class PurchaseHistoryRecordWrapper { final String signature; /// The product ID of this purchase. + /// + /// This property is deprecated. Use `skus` instead. @JsonKey(defaultValue: '') final String sku; + /// The product ID of this purchase. + @JsonKey(defaultValue: []) + final List skus; + /// Details about this purchase, in JSON. /// /// This can be used verify a purchase. See ["Verify a purchase on a diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart index 5815a866c82d..e724960518bc 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart @@ -13,6 +13,7 @@ PurchaseWrapper _$PurchaseWrapperFromJson(Map json) => PurchaseWrapper( purchaseToken: json['purchaseToken'] as String? ?? '', signature: json['signature'] as String? ?? '', sku: json['sku'] as String? ?? '', + skus: json['skus'] as List? ?? [], isAutoRenewing: json['isAutoRenewing'] as bool, originalJson: json['originalJson'] as String? ?? '', developerPayload: json['developerPayload'] as String?, @@ -29,6 +30,7 @@ PurchaseHistoryRecordWrapper _$PurchaseHistoryRecordWrapperFromJson(Map json) => purchaseToken: json['purchaseToken'] as String? ?? '', signature: json['signature'] as String? ?? '', sku: json['sku'] as String? ?? '', + skus: json['skus'] as List? ?? [], originalJson: json['originalJson'] as String? ?? '', developerPayload: json['developerPayload'] as String?, ); From eb5ccfb1b25ebffe46123e49c87fe75b1644d7d7 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Thu, 9 Jun 2022 11:28:58 -0700 Subject: [PATCH 12/22] Use annotations --- .../lib/src/billing_client_wrappers/purchase_wrapper.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart index 52ff42b5a2ff..65db3eb6e612 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart @@ -105,9 +105,8 @@ class PurchaseWrapper { final String signature; /// The product ID of this purchase. - /// - /// This property is deprecated. Use `skus` instead. @JsonKey(defaultValue: '') + @Deprecated('Use skus instead') final String sku; /// The product IDs of this purchase. @@ -209,9 +208,8 @@ class PurchaseHistoryRecordWrapper { final String signature; /// The product ID of this purchase. - /// - /// This property is deprecated. Use `skus` instead. @JsonKey(defaultValue: '') + @Deprecated('Use skus instead') final String sku; /// The product ID of this purchase. From f394c10cc181e0429d1536a7738695223ea762ec Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Fri, 10 Jun 2022 14:51:29 -0700 Subject: [PATCH 13/22] Tests --- .../inapppurchase/MethodCallHandlerImpl.java | 2 +- .../inapppurchase/MethodCallHandlerTest.java | 27 ++++++++++++++----- .../purchase_wrapper.dart | 2 ++ .../purchase_wrapper_test.dart | 4 +++ 4 files changed, 27 insertions(+), 8 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 8e65c9cd70d9..b4b873cfc97d 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 @@ -331,7 +331,7 @@ private void queryPurchaseHistoryAsync(String skuType, final MethodChannel.Resul } billingClient.queryPurchaseHistoryAsync( - skuType, + QueryPurchasesParams.newBuilder().setProductType(skuType).build(), new PurchaseHistoryResponseListener() { @Override public void onPurchaseHistoryResponse( 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 644b7fc8fc36..87a5a2bf637f 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 @@ -23,6 +23,7 @@ import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesResult; import static io.flutter.plugins.inapppurchase.Translator.fromSkuDetailsList; import static java.util.Arrays.asList; +import static java.util.Collections.list; import static java.util.Collections.singletonList; import static java.util.Collections.unmodifiableList; import static java.util.stream.Collectors.toList; @@ -527,9 +528,6 @@ public void launchBillingFlow_ok_Full() { verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); assertEquals(params.getSku(), skuId); - assertEquals(params.getOldSku(), oldSkuId); - assertEquals(params.getOldSkuPurchaseToken(), purchaseToken); - assertEquals(params.getReplaceSkusProrationMode(), prorationMode); // Verify we pass the response code to result verify(result, never()).error(any(), any(), any()); @@ -595,7 +593,7 @@ public void launchBillingFlow_oldSkuNotFound() { } @Test - public void queryPurchases() { + public void queryPurchasesAsync() { establishConnectedBillingClient(null, null); PurchasesResult purchasesResult = mock(PurchasesResult.class); Purchase purchase = buildPurchase("foo"); @@ -606,11 +604,26 @@ public void queryPurchases() { .setDebugMessage("dummy debug message") .build(); when(purchasesResult.getBillingResult()).thenReturn(billingResult); - when(mockBillingClient.queryPurchases(SkuType.INAPP)).thenReturn(purchasesResult); + when(mockBillingClient.queryPurchasesAsync( + any(QueryPurchasesParams.class), + any(PurchaseHistoryResponseListener.class) + ).thenAnswer( + new Answer() { + Object answer(InvocationOnMock invocation) { + BillingResult.Builder builder = BillingResult.newBuilder(); + builder.setDebugMessage("debug message"); + builder.setResponseCode(10); + ((Callback) invocation.getArguments()[1]).onPurchaseHistoryResponse( + builder.build(), + List.of(PurchaseHistoryRecord("{}", "signature")) + ); + return null; + } + }); HashMap arguments = new HashMap<>(); arguments.put("skuType", SkuType.INAPP); - methodChannelHandler.onMethodCall(new MethodCall(QUERY_PURCHASES, arguments), result); + methodChannelHandler.onMethodCall(new MethodCall(QUERY_PURCHASES_ASYNC, arguments), result); // Verify we pass the response to result ArgumentCaptor> resultCaptor = ArgumentCaptor.forClass(HashMap.class); @@ -626,7 +639,7 @@ public void queryPurchases_clientDisconnected() { HashMap arguments = new HashMap<>(); arguments.put("skuType", SkuType.INAPP); - methodChannelHandler.onMethodCall(new MethodCall(QUERY_PURCHASES, arguments), result); + methodChannelHandler.onMethodCall(new MethodCall(QUERY_PURCHASES_ASYNC, arguments), result); // Assert that we sent an error back. verify(result).error(contains("UNAVAILABLE"), contains("BillingClient"), any()); diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart index 65db3eb6e612..2f52b7a454f0 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart @@ -33,6 +33,7 @@ class PurchaseWrapper { required this.purchaseTime, required this.purchaseToken, required this.signature, + @Deprecated('Use skus instead') this.sku = '', // Deprecated required this.skus, required this.isAutoRenewing, @@ -184,6 +185,7 @@ class PurchaseHistoryRecordWrapper { required this.purchaseTime, required this.purchaseToken, required this.signature, + @Deprecated('Use skus instead') this.sku = '', // Deprecated required this.skus, required this.originalJson, 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 65c8bb213cc4..bb3c11fe1a62 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 @@ -12,6 +12,7 @@ const PurchaseWrapper dummyPurchase = PurchaseWrapper( purchaseTime: 0, signature: 'signature', sku: 'sku', + skus: ['sku'], purchaseToken: 'purchaseToken', isAutoRenewing: false, originalJson: '', @@ -28,6 +29,7 @@ const PurchaseWrapper dummyUnacknowledgedPurchase = PurchaseWrapper( purchaseTime: 0, signature: 'signature', sku: 'sku', + skus: ['sku'], purchaseToken: 'purchaseToken', isAutoRenewing: false, originalJson: '', @@ -41,6 +43,7 @@ const PurchaseHistoryRecordWrapper dummyPurchaseHistoryRecord = purchaseTime: 0, signature: 'signature', sku: 'sku', + skus: ['sku'], purchaseToken: 'purchaseToken', originalJson: '', developerPayload: 'dummy payload', @@ -52,6 +55,7 @@ const PurchaseWrapper dummyOldPurchase = PurchaseWrapper( purchaseTime: 0, signature: 'oldSignature', sku: 'oldSku', + skus: ['oldSku'], purchaseToken: 'oldPurchaseToken', isAutoRenewing: false, originalJson: '', From 41e01ee84b446ca4491963d5dd4f6bc3f1d76d8c Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Fri, 10 Jun 2022 15:19:14 -0700 Subject: [PATCH 14/22] Compiling --- .../flutter/plugins/inapppurchase/MethodCallHandlerImpl.java | 3 ++- 1 file changed, 2 insertions(+), 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 b4b873cfc97d..8a94856355f6 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 @@ -32,6 +32,7 @@ import com.android.billingclient.api.SkuDetails; import com.android.billingclient.api.SkuDetailsParams; import com.android.billingclient.api.SkuDetailsResponseListener; +import com.android.billingclient.api.QueryPurchaseHistoryParams; import com.android.billingclient.api.QueryPurchasesParams; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -331,7 +332,7 @@ private void queryPurchaseHistoryAsync(String skuType, final MethodChannel.Resul } billingClient.queryPurchaseHistoryAsync( - QueryPurchasesParams.newBuilder().setProductType(skuType).build(), + QueryPurchaseHistoryParams.newBuilder().setProductType(skuType).build(), new PurchaseHistoryResponseListener() { @Override public void onPurchaseHistoryResponse( From da9e0d679a6f50f9a94a437a5069c870af498db9 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Fri, 10 Jun 2022 15:23:17 -0700 Subject: [PATCH 15/22] Tests compiling --- .../flutter/plugins/inapppurchase/MethodCallHandlerTest.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 87a5a2bf637f..b421936d0de9 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 @@ -607,7 +607,7 @@ public void queryPurchasesAsync() { when(mockBillingClient.queryPurchasesAsync( any(QueryPurchasesParams.class), any(PurchaseHistoryResponseListener.class) - ).thenAnswer( + )).thenAnswer( new Answer() { Object answer(InvocationOnMock invocation) { BillingResult.Builder builder = BillingResult.newBuilder(); @@ -619,7 +619,8 @@ Object answer(InvocationOnMock invocation) { ); return null; } - }); + } + ); HashMap arguments = new HashMap<>(); arguments.put("skuType", SkuType.INAPP); From 5133ea99c89b442c06cae475d33e7160ba84bad7 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Thu, 7 Jul 2022 11:26:13 -0500 Subject: [PATCH 16/22] Migrate tests --- .../inapppurchase/MethodCallHandlerImpl.java | 1 + .../inapppurchase/MethodCallHandlerTest.java | 55 +------------------ .../plugins/inapppurchase/TranslatorTest.java | 38 ++----------- 3 files changed, 6 insertions(+), 88 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 8a94856355f6..a90fa60753bd 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 @@ -184,6 +184,7 @@ private void isReady(MethodChannel.Result result) { result.success(billingClient.isReady()); } + // TODO(garyq): Migrate to new subscriptions API: https://developer.android.com/google/play/billing/migrate-gpblv5 private void querySkuDetailsAsync( final String skuType, final List skusList, final MethodChannel.Result result) { if (billingClientError(result)) { 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 b421936d0de9..3aaf80cb3ded 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 @@ -14,13 +14,13 @@ import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.ON_DISCONNECT; import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.ON_PURCHASES_UPDATED; import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.QUERY_PURCHASES; +import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.QUERY_PURCHASES_ASYNC; import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.QUERY_PURCHASE_HISTORY_ASYNC; import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.QUERY_SKU_DETAILS; import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.START_CONNECTION; import static io.flutter.plugins.inapppurchase.Translator.fromBillingResult; import static io.flutter.plugins.inapppurchase.Translator.fromPurchaseHistoryRecordList; import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesList; -import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesResult; import static io.flutter.plugins.inapppurchase.Translator.fromSkuDetailsList; import static java.util.Arrays.asList; import static java.util.Collections.list; @@ -57,7 +57,6 @@ import com.android.billingclient.api.PriceChangeConfirmationListener; import com.android.billingclient.api.PriceChangeFlowParams; import com.android.billingclient.api.Purchase; -import com.android.billingclient.api.Purchase.PurchasesResult; import com.android.billingclient.api.PurchaseHistoryRecord; import com.android.billingclient.api.PurchaseHistoryResponseListener; import com.android.billingclient.api.SkuDetails; @@ -295,7 +294,6 @@ public void launchBillingFlow_null_AccountId_do_not_crash() { ArgumentCaptor.forClass(BillingFlowParams.class); verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); - assertEquals(params.getSku(), skuId); // Verify we pass the response code to result verify(result, never()).error(any(), any(), any()); @@ -328,8 +326,6 @@ public void launchBillingFlow_ok_null_OldSku() { ArgumentCaptor.forClass(BillingFlowParams.class); verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); - assertEquals(params.getSku(), skuId); - assertNull(params.getOldSku()); // Verify we pass the response code to result verify(result, never()).error(any(), any(), any()); verify(result, times(1)).success(fromBillingResult(billingResult)); @@ -381,8 +377,6 @@ public void launchBillingFlow_ok_oldSku() { ArgumentCaptor.forClass(BillingFlowParams.class); verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); - assertEquals(params.getSku(), skuId); - assertEquals(params.getOldSku(), oldSkuId); // Verify we pass the response code to result verify(result, never()).error(any(), any(), any()); @@ -414,7 +408,6 @@ public void launchBillingFlow_ok_AccountId() { ArgumentCaptor.forClass(BillingFlowParams.class); verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); - assertEquals(params.getSku(), skuId); // Verify we pass the response code to result verify(result, never()).error(any(), any(), any()); @@ -452,10 +445,6 @@ public void launchBillingFlow_ok_Proration() { ArgumentCaptor.forClass(BillingFlowParams.class); verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); - assertEquals(params.getSku(), skuId); - assertEquals(params.getOldSku(), oldSkuId); - assertEquals(params.getOldSkuPurchaseToken(), purchaseToken); - assertEquals(params.getReplaceSkusProrationMode(), prorationMode); // Verify we pass the response code to result verify(result, never()).error(any(), any(), any()); @@ -527,7 +516,6 @@ public void launchBillingFlow_ok_Full() { ArgumentCaptor.forClass(BillingFlowParams.class); verify(mockBillingClient).launchBillingFlow(any(), billingFlowParamsCaptor.capture()); BillingFlowParams params = billingFlowParamsCaptor.getValue(); - assertEquals(params.getSku(), skuId); // Verify we pass the response code to result verify(result, never()).error(any(), any(), any()); @@ -592,47 +580,6 @@ public void launchBillingFlow_oldSkuNotFound() { verify(result, never()).success(any()); } - @Test - public void queryPurchasesAsync() { - establishConnectedBillingClient(null, null); - PurchasesResult purchasesResult = mock(PurchasesResult.class); - Purchase purchase = buildPurchase("foo"); - when(purchasesResult.getPurchasesList()).thenReturn(asList(purchase)); - BillingResult billingResult = - BillingResult.newBuilder() - .setResponseCode(100) - .setDebugMessage("dummy debug message") - .build(); - when(purchasesResult.getBillingResult()).thenReturn(billingResult); - when(mockBillingClient.queryPurchasesAsync( - any(QueryPurchasesParams.class), - any(PurchaseHistoryResponseListener.class) - )).thenAnswer( - new Answer() { - Object answer(InvocationOnMock invocation) { - BillingResult.Builder builder = BillingResult.newBuilder(); - builder.setDebugMessage("debug message"); - builder.setResponseCode(10); - ((Callback) invocation.getArguments()[1]).onPurchaseHistoryResponse( - builder.build(), - List.of(PurchaseHistoryRecord("{}", "signature")) - ); - return null; - } - } - ); - - HashMap arguments = new HashMap<>(); - arguments.put("skuType", SkuType.INAPP); - methodChannelHandler.onMethodCall(new MethodCall(QUERY_PURCHASES_ASYNC, arguments), result); - - // Verify we pass the response to result - ArgumentCaptor> resultCaptor = ArgumentCaptor.forClass(HashMap.class); - verify(result, never()).error(any(), any(), any()); - verify(result, times(1)).success(resultCaptor.capture()); - assertEquals(fromPurchasesResult(purchasesResult), resultCaptor.getValue()); - } - @Test public void queryPurchases_clientDisconnected() { // Prepare the launch call after disconnecting the client diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java index 2837dceea652..d0327669fc27 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java @@ -17,7 +17,6 @@ import com.android.billingclient.api.BillingClient; import com.android.billingclient.api.BillingResult; import com.android.billingclient.api.Purchase; -import com.android.billingclient.api.Purchase.PurchasesResult; import com.android.billingclient.api.PurchaseHistoryRecord; import com.android.billingclient.api.SkuDetails; import java.util.Arrays; @@ -138,37 +137,6 @@ public void fromPurchasesList_null() { assertEquals(Collections.emptyList(), Translator.fromPurchasesList(null)); } - @Test - public void fromPurchasesResult() throws JSONException { - PurchasesResult result = mock(PurchasesResult.class); - final String purchase2Json = - "{\"orderId\":\"foo2\",\"packageName\":\"bar\",\"productId\":\"consumable\",\"purchaseTime\":11111111,\"purchaseState\":0,\"purchaseToken\":\"baz\",\"developerPayload\":\"dummy payload\",\"isAcknowledged\":\"true\"}"; - final String signature = "signature"; - final List expectedPurchases = - Arrays.asList( - new Purchase(PURCHASE_EXAMPLE_JSON, signature), new Purchase(purchase2Json, signature)); - when(result.getPurchasesList()).thenReturn(expectedPurchases); - when(result.getResponseCode()).thenReturn(BillingClient.BillingResponseCode.OK); - BillingResult newBillingResult = - BillingResult.newBuilder() - .setDebugMessage("dummy debug message") - .setResponseCode(BillingClient.BillingResponseCode.OK) - .build(); - when(result.getBillingResult()).thenReturn(newBillingResult); - final HashMap serialized = Translator.fromPurchasesResult(result); - - assertEquals(BillingClient.BillingResponseCode.OK, serialized.get("responseCode")); - List> serializedPurchases = - (List>) serialized.get("purchasesList"); - assertEquals(expectedPurchases.size(), serializedPurchases.size()); - assertSerialized(expectedPurchases.get(0), serializedPurchases.get(0)); - assertSerialized(expectedPurchases.get(1), serializedPurchases.get(1)); - - Map billingResultMap = (Map) serialized.get("billingResult"); - assertEquals(billingResultMap.get("responseCode"), newBillingResult.getResponseCode()); - assertEquals(billingResultMap.get("debugMessage"), newBillingResult.getDebugMessage()); - } - @Test public void fromBillingResult() throws JSONException { BillingResult newBillingResult = @@ -232,7 +200,8 @@ private void assertSerialized(Purchase expected, Map serialized) assertEquals(expected.getPurchaseToken(), serialized.get("purchaseToken")); assertEquals(expected.getSignature(), serialized.get("signature")); assertEquals(expected.getOriginalJson(), serialized.get("originalJson")); - assertEquals(expected.getSku(), serialized.get("sku")); + assertEquals(expected.getSkus().get(0), serialized.get("sku")); + assertEquals(expected.getSkus(), serialized.get("skus")); assertEquals(expected.getDeveloperPayload(), serialized.get("developerPayload")); assertEquals(expected.isAcknowledged(), serialized.get("isAcknowledged")); assertEquals(expected.getPurchaseState(), serialized.get("purchaseState")); @@ -251,7 +220,8 @@ private void assertSerialized(PurchaseHistoryRecord expected, Map Date: Thu, 7 Jul 2022 15:37:15 -0500 Subject: [PATCH 17/22] Dart-side handling of sku->skus --- .../flutter/plugins/inapppurchase/Translator.java | 14 -------------- .../billing_client_wrappers/purchase_wrapper.dart | 9 +++++---- .../purchase_wrapper.g.dart | 2 -- 3 files changed, 5 insertions(+), 20 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 a2da36be9228..5a0cf6ea3727 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 @@ -61,13 +61,6 @@ static HashMap fromPurchase(Purchase purchase) { info.put("purchaseTime", purchase.getPurchaseTime()); info.put("purchaseToken", purchase.getPurchaseToken()); info.put("signature", purchase.getSignature()); - // TODO(garyq): Remove deprecated `sku`. - // `sku` was deprecated in billion 4.0, but we cannot directly remove it from our - // API instantly. Thus, for backwards compatibility, we pass the first sku here - // and include the rest of the list under `skus`. - if (!skus.isEmpty()) { - info.put("sku", skus.get(0)); - } info.put("skus", skus); info.put("isAutoRenewing", purchase.isAutoRenewing()); info.put("originalJson", purchase.getOriginalJson()); @@ -90,13 +83,6 @@ static HashMap fromPurchaseHistoryRecord( info.put("purchaseTime", purchaseHistoryRecord.getPurchaseTime()); info.put("purchaseToken", purchaseHistoryRecord.getPurchaseToken()); info.put("signature", purchaseHistoryRecord.getSignature()); - // TODO(garyq): Remove deprecated `sku`. - // `sku` was deprecated in billion 4.0, but we cannot directly remove it from our - // API instantly. Thus, for backwards compatibility, we pass the first sku here - // and include the rest of the list under `skus`. - if (!skus.isEmpty()) { - info.put("sku", skus.get(0)); - } info.put("skus", skus); info.put("developerPayload", purchaseHistoryRecord.getDeveloperPayload()); info.put("originalJson", purchaseHistoryRecord.getOriginalJson()); diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart index 2f52b7a454f0..45f017bcaaf1 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart @@ -34,8 +34,8 @@ class PurchaseWrapper { required this.purchaseToken, required this.signature, @Deprecated('Use skus instead') - this.sku = '', // Deprecated - required this.skus, + String? sku, // Deprecated + this.skus, required this.isAutoRenewing, required this.originalJson, this.developerPayload, @@ -43,7 +43,7 @@ class PurchaseWrapper { required this.purchaseState, this.obfuscatedAccountId, this.obfuscatedProfileId, - }); + }) : _sku(sku); /// Factory for creating a [PurchaseWrapper] from a [Map] with the purchase details. factory PurchaseWrapper.fromJson(Map map) => @@ -108,7 +108,8 @@ class PurchaseWrapper { /// The product ID of this purchase. @JsonKey(defaultValue: '') @Deprecated('Use skus instead') - final String sku; + final String get sku => _sku ?? skus.first; + final String? _sku; /// The product IDs of this purchase. @JsonKey(defaultValue: []) diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart index e724960518bc..8a8efa111a7e 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart @@ -12,7 +12,6 @@ PurchaseWrapper _$PurchaseWrapperFromJson(Map json) => PurchaseWrapper( purchaseTime: json['purchaseTime'] as int? ?? 0, purchaseToken: json['purchaseToken'] as String? ?? '', signature: json['signature'] as String? ?? '', - sku: json['sku'] as String? ?? '', skus: json['skus'] as List? ?? [], isAutoRenewing: json['isAutoRenewing'] as bool, originalJson: json['originalJson'] as String? ?? '', @@ -29,7 +28,6 @@ PurchaseHistoryRecordWrapper _$PurchaseHistoryRecordWrapperFromJson(Map json) => purchaseTime: json['purchaseTime'] as int? ?? 0, purchaseToken: json['purchaseToken'] as String? ?? '', signature: json['signature'] as String? ?? '', - sku: json['sku'] as String? ?? '', skus: json['skus'] as List? ?? [], originalJson: json['originalJson'] as String? ?? '', developerPayload: json['developerPayload'] as String?, From ce911968546398f81e24e5293df573ec244f4eb2 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Thu, 7 Jul 2022 22:50:28 -0500 Subject: [PATCH 18/22] Move skus handling to dart, fix tests --- .../plugins/inapppurchase/MethodCallHandlerImpl.java | 12 ++++++------ .../plugins/inapppurchase/MethodCallHandlerTest.java | 5 ++++- .../plugins/inapppurchase/TranslatorTest.java | 2 -- .../billing_client_wrappers/purchase_wrapper.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/MethodCallHandlerImpl.java b/packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java index a90fa60753bd..6fa24a2409e6 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 @@ -142,6 +142,7 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) { queryPurchasesAsync((String) call.argument("skuType"), result); break; case InAppPurchasePlugin.MethodNames.QUERY_PURCHASE_HISTORY_ASYNC: + Log.e("flutter", (String) call.argument("skuType")); queryPurchaseHistoryAsync((String) call.argument("skuType"), result); break; case InAppPurchasePlugin.MethodNames.CONSUME_PURCHASE_ASYNC: @@ -219,7 +220,6 @@ private void launchBillingFlow( if (billingClientError(result)) { return; } - SkuDetails skuDetails = cachedSkus.get(sku); if (skuDetails == null) { result.error( @@ -266,13 +266,13 @@ private void launchBillingFlow( if (obfuscatedProfileId != null && !obfuscatedProfileId.isEmpty()) { paramsBuilder.setObfuscatedProfileId(obfuscatedProfileId); } - if (oldSku != null && !oldSku.isEmpty()) { - BillingFlowParams.SubscriptionUpdateParams.Builder subscriptionUpdateParamsBuilder = - BillingFlowParams.SubscriptionUpdateParams.newBuilder(); - subscriptionUpdateParamsBuilder.setOldSkuPurchaseToken(purchaseToken); + BillingFlowParams.SubscriptionUpdateParams.Builder subscriptionUpdateParamsBuilder = + BillingFlowParams.SubscriptionUpdateParams.newBuilder(); + if (oldSku != null && !oldSku.isEmpty() && purchaseToken != null) { + subscriptionUpdateParamsBuilder.setOldPurchaseToken(purchaseToken); // The proration mode value has to match one of the following declared in // https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode - subscriptionUpdateParamsBuilder.setReplaceSkusProrationMode(prorationMode); + subscriptionUpdateParamsBuilder.setReplaceProrationMode(prorationMode); paramsBuilder.setSubscriptionUpdateParams(subscriptionUpdateParamsBuilder.build()); } result.success( 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 3aaf80cb3ded..7634e0ee7418 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 @@ -41,6 +41,8 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.util.Log; + import android.app.Activity; import android.content.Context; import androidx.annotation.NonNull; @@ -62,6 +64,7 @@ import com.android.billingclient.api.SkuDetails; import com.android.billingclient.api.SkuDetailsParams; import com.android.billingclient.api.SkuDetailsResponseListener; +import com.android.billingclient.api.QueryPurchaseHistoryParams; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -615,7 +618,7 @@ public void queryPurchaseHistoryAsync() { // Verify we pass the data to result verify(mockBillingClient) - .queryPurchaseHistoryAsync(eq(SkuType.INAPP), listenerCaptor.capture()); + .queryPurchaseHistoryAsync(any(QueryPurchaseHistoryParams.class), listenerCaptor.capture()); listenerCaptor.getValue().onPurchaseHistoryResponse(billingResult, purchasesList); verify(result).success(resultCaptor.capture()); HashMap resultData = resultCaptor.getValue(); diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java index d0327669fc27..28117b779e19 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java @@ -200,7 +200,6 @@ private void assertSerialized(Purchase expected, Map serialized) assertEquals(expected.getPurchaseToken(), serialized.get("purchaseToken")); assertEquals(expected.getSignature(), serialized.get("signature")); assertEquals(expected.getOriginalJson(), serialized.get("originalJson")); - assertEquals(expected.getSkus().get(0), serialized.get("sku")); assertEquals(expected.getSkus(), serialized.get("skus")); assertEquals(expected.getDeveloperPayload(), serialized.get("developerPayload")); assertEquals(expected.isAcknowledged(), serialized.get("isAcknowledged")); @@ -220,7 +219,6 @@ private void assertSerialized(PurchaseHistoryRecord expected, Map map) => @@ -108,7 +108,7 @@ class PurchaseWrapper { /// The product ID of this purchase. @JsonKey(defaultValue: '') @Deprecated('Use skus instead') - final String get sku => _sku ?? skus.first; + String get sku => _sku ?? skus.first; final String? _sku; /// The product IDs of this purchase. From d711db33e37049fa251b8964f265219f844a4374 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Fri, 8 Jul 2022 00:42:42 -0500 Subject: [PATCH 19/22] Fix dart tests --- .../plugins/inapppurchase/MethodCallHandlerTest.java | 2 -- .../billing_client_wrappers/purchase_wrapper.dart | 12 ++++++------ .../billing_client_wrappers/purchase_wrapper.g.dart | 6 ++++-- .../purchase_wrapper_test.dart | 8 ++------ .../test/in_app_purchase_android_platform_test.dart | 6 +++--- 5 files changed, 15 insertions(+), 19 deletions(-) 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 7634e0ee7418..d9ff61f35208 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 @@ -41,8 +41,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.util.Log; - import android.app.Activity; import android.content.Context; import androidx.annotation.NonNull; diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart index 57f20cbec21d..6f7e3cde95c2 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart @@ -106,9 +106,8 @@ class PurchaseWrapper { final String signature; /// The product ID of this purchase. - @JsonKey(defaultValue: '') @Deprecated('Use skus instead') - String get sku => _sku ?? skus.first; + String get sku => _sku ?? (skus.isNotEmpty ? skus.first : ''); final String? _sku; /// The product IDs of this purchase. @@ -187,11 +186,11 @@ class PurchaseHistoryRecordWrapper { required this.purchaseToken, required this.signature, @Deprecated('Use skus instead') - this.sku = '', // Deprecated + String? sku, // Deprecated required this.skus, required this.originalJson, required this.developerPayload, - }); + }) : _sku = sku; /// Factory for creating a [PurchaseHistoryRecordWrapper] from a [Map] with the record details. factory PurchaseHistoryRecordWrapper.fromJson(Map map) => @@ -211,9 +210,10 @@ class PurchaseHistoryRecordWrapper { final String signature; /// The product ID of this purchase. - @JsonKey(defaultValue: '') @Deprecated('Use skus instead') - final String sku; + String get sku => _sku ?? (skus.isNotEmpty ? skus.first : ''); + + final String? _sku; /// The product ID of this purchase. @JsonKey(defaultValue: []) diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart index 8a8efa111a7e..f16bd5271fe0 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart @@ -12,7 +12,8 @@ PurchaseWrapper _$PurchaseWrapperFromJson(Map json) => PurchaseWrapper( purchaseTime: json['purchaseTime'] as int? ?? 0, purchaseToken: json['purchaseToken'] as String? ?? '', signature: json['signature'] as String? ?? '', - skus: json['skus'] as List? ?? [], + skus: json['skus'] != null ? (json['skus'] as List)?.map((item) => item as String)?.toList() ?? [] : [], + // skus: json['skus'] as List? ?? [], isAutoRenewing: json['isAutoRenewing'] as bool, originalJson: json['originalJson'] as String? ?? '', developerPayload: json['developerPayload'] as String?, @@ -28,7 +29,8 @@ PurchaseHistoryRecordWrapper _$PurchaseHistoryRecordWrapperFromJson(Map json) => purchaseTime: json['purchaseTime'] as int? ?? 0, purchaseToken: json['purchaseToken'] as String? ?? '', signature: json['signature'] as String? ?? '', - skus: json['skus'] as List? ?? [], + skus: json['skus'] != null ? (json['skus'] as List)?.map((item) => item as String)?.toList() ?? [] : [], + // skus: json['skus'] as List? ?? [], originalJson: json['originalJson'] as String? ?? '', developerPayload: json['developerPayload'] as String?, ); 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 bb3c11fe1a62..184d9331e6c1 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 @@ -11,7 +11,6 @@ const PurchaseWrapper dummyPurchase = PurchaseWrapper( packageName: 'packageName', purchaseTime: 0, signature: 'signature', - sku: 'sku', skus: ['sku'], purchaseToken: 'purchaseToken', isAutoRenewing: false, @@ -28,7 +27,6 @@ const PurchaseWrapper dummyUnacknowledgedPurchase = PurchaseWrapper( packageName: 'packageName', purchaseTime: 0, signature: 'signature', - sku: 'sku', skus: ['sku'], purchaseToken: 'purchaseToken', isAutoRenewing: false, @@ -42,7 +40,6 @@ const PurchaseHistoryRecordWrapper dummyPurchaseHistoryRecord = PurchaseHistoryRecordWrapper( purchaseTime: 0, signature: 'signature', - sku: 'sku', skus: ['sku'], purchaseToken: 'purchaseToken', originalJson: '', @@ -54,7 +51,6 @@ const PurchaseWrapper dummyOldPurchase = PurchaseWrapper( packageName: 'oldPackageName', purchaseTime: 0, signature: 'oldSignature', - sku: 'oldSku', skus: ['oldSku'], purchaseToken: 'oldPurchaseToken', isAutoRenewing: false, @@ -209,7 +205,7 @@ Map buildPurchaseMap(PurchaseWrapper original) { 'packageName': original.packageName, 'purchaseTime': original.purchaseTime, 'signature': original.signature, - 'sku': original.sku, + 'skus': original.skus, 'purchaseToken': original.purchaseToken, 'isAutoRenewing': original.isAutoRenewing, 'originalJson': original.originalJson, @@ -227,7 +223,7 @@ Map buildPurchaseHistoryRecordMap( return { 'purchaseTime': original.purchaseTime, 'signature': original.signature, - 'sku': original.sku, + 'skus': original.skus, 'purchaseToken': original.purchaseToken, 'originalJson': original.originalJson, 'developerPayload': original.developerPayload, diff --git a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart index b19d631092e7..30c7187f8444 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart @@ -299,7 +299,7 @@ void main() { 'purchasesList': [ { 'orderId': 'orderID1', - 'sku': skuDetails.sku, + 'skus': [skuDetails.sku], 'isAutoRenewing': false, 'packageName': 'package', 'purchaseTime': 1231231231, @@ -515,7 +515,7 @@ void main() { 'purchasesList': [ { 'orderId': 'orderID1', - 'sku': skuDetails.sku, + 'skus': [skuDetails.sku], 'isAutoRenewing': false, 'packageName': 'package', 'purchaseTime': 1231231231, @@ -592,7 +592,7 @@ void main() { 'purchasesList': [ { 'orderId': 'orderID1', - 'sku': skuDetails.sku, + 'skus': [skuDetails.sku], 'isAutoRenewing': false, 'packageName': 'package', 'purchaseTime': 1231231231, From 73cd064642ba9bb04d33115fcce2539f2e23c187 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Fri, 8 Jul 2022 00:48:24 -0500 Subject: [PATCH 20/22] formatting --- .../inapppurchase/MethodCallHandlerImpl.java | 27 +++++++++---------- .../inapppurchase/MethodCallHandlerTest.java | 5 +--- .../plugins/inapppurchase/TranslatorTest.java | 2 -- .../purchase_wrapper.dart | 6 ++--- 4 files changed, 16 insertions(+), 24 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 6fa24a2409e6..ab12b2db8630 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 @@ -29,11 +29,11 @@ import com.android.billingclient.api.PurchaseHistoryRecord; import com.android.billingclient.api.PurchaseHistoryResponseListener; import com.android.billingclient.api.PurchasesResponseListener; +import com.android.billingclient.api.QueryPurchaseHistoryParams; +import com.android.billingclient.api.QueryPurchasesParams; import com.android.billingclient.api.SkuDetails; import com.android.billingclient.api.SkuDetailsParams; import com.android.billingclient.api.SkuDetailsResponseListener; -import com.android.billingclient.api.QueryPurchaseHistoryParams; -import com.android.billingclient.api.QueryPurchasesParams; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import java.util.HashMap; @@ -312,18 +312,17 @@ private void queryPurchasesAsync(String skuType, MethodChannel.Result result) { billingClient.queryPurchasesAsync( paramsBuilder.build(), new PurchasesResponseListener() { - @Override - public void onQueryPurchasesResponse( - BillingResult billingResult, List purchasesList) { - final Map serialized = new HashMap<>(); - // The response code is no longer passed, as part of billing 4.0, so we pass OK here - // as success is implied by calling this callback. - serialized.put("responseCode", BillingClient.BillingResponseCode.OK); - serialized.put("billingResult", Translator.fromBillingResult(billingResult)); - serialized.put( - "purchaseList", fromPurchasesList(purchasesList)); - result.success(serialized); - } + @Override + public void onQueryPurchasesResponse( + BillingResult billingResult, List purchasesList) { + final Map serialized = new HashMap<>(); + // The response code is no longer passed, as part of billing 4.0, so we pass OK here + // as success is implied by calling this callback. + serialized.put("responseCode", BillingClient.BillingResponseCode.OK); + serialized.put("billingResult", Translator.fromBillingResult(billingResult)); + serialized.put("purchaseList", fromPurchasesList(purchasesList)); + result.success(serialized); + } }); } 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 d9ff61f35208..e99ff46dd2cc 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 @@ -13,7 +13,6 @@ import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.LAUNCH_PRICE_CHANGE_CONFIRMATION_FLOW; import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.ON_DISCONNECT; import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.ON_PURCHASES_UPDATED; -import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.QUERY_PURCHASES; import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.QUERY_PURCHASES_ASYNC; import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.QUERY_PURCHASE_HISTORY_ASYNC; import static io.flutter.plugins.inapppurchase.InAppPurchasePlugin.MethodNames.QUERY_SKU_DETAILS; @@ -23,12 +22,10 @@ import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesList; import static io.flutter.plugins.inapppurchase.Translator.fromSkuDetailsList; import static java.util.Arrays.asList; -import static java.util.Collections.list; import static java.util.Collections.singletonList; import static java.util.Collections.unmodifiableList; import static java.util.stream.Collectors.toList; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.contains; @@ -59,10 +56,10 @@ import com.android.billingclient.api.Purchase; import com.android.billingclient.api.PurchaseHistoryRecord; import com.android.billingclient.api.PurchaseHistoryResponseListener; +import com.android.billingclient.api.QueryPurchaseHistoryParams; import com.android.billingclient.api.SkuDetails; import com.android.billingclient.api.SkuDetailsParams; import com.android.billingclient.api.SkuDetailsResponseListener; -import com.android.billingclient.api.QueryPurchaseHistoryParams; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; diff --git a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java index 28117b779e19..79852e7e8ca5 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java +++ b/packages/in_app_purchase/in_app_purchase_android/android/src/test/java/io/flutter/plugins/inapppurchase/TranslatorTest.java @@ -9,8 +9,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import androidx.annotation.NonNull; import com.android.billingclient.api.AccountIdentifiers; diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart index 6f7e3cde95c2..af1aaa5d556a 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.dart @@ -33,8 +33,7 @@ class PurchaseWrapper { required this.purchaseTime, required this.purchaseToken, required this.signature, - @Deprecated('Use skus instead') - String? sku, // Deprecated + @Deprecated('Use skus instead') String? sku, required this.skus, required this.isAutoRenewing, required this.originalJson, @@ -185,8 +184,7 @@ class PurchaseHistoryRecordWrapper { required this.purchaseTime, required this.purchaseToken, required this.signature, - @Deprecated('Use skus instead') - String? sku, // Deprecated + @Deprecated('Use skus instead') String? sku, required this.skus, required this.originalJson, required this.developerPayload, From 8c79e71e182368f9e158029a843ff65a5c8ee288 Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Fri, 8 Jul 2022 01:17:52 -0500 Subject: [PATCH 21/22] Formatting and test fixes --- .../billing_client_wrappers/purchase_wrapper.g.dart | 12 ++++++++---- .../test/in_app_purchase_android_platform_test.dart | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart index f16bd5271fe0..7f6fd0f61d94 100644 --- a/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart +++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/billing_client_wrappers/purchase_wrapper.g.dart @@ -12,8 +12,10 @@ PurchaseWrapper _$PurchaseWrapperFromJson(Map json) => PurchaseWrapper( purchaseTime: json['purchaseTime'] as int? ?? 0, purchaseToken: json['purchaseToken'] as String? ?? '', signature: json['signature'] as String? ?? '', - skus: json['skus'] != null ? (json['skus'] as List)?.map((item) => item as String)?.toList() ?? [] : [], - // skus: json['skus'] as List? ?? [], + skus: json['skus'] != null + ? (json['skus'] as List)?.map((item) => item as String)?.toList() ?? + [] + : [], isAutoRenewing: json['isAutoRenewing'] as bool, originalJson: json['originalJson'] as String? ?? '', developerPayload: json['developerPayload'] as String?, @@ -29,8 +31,10 @@ PurchaseHistoryRecordWrapper _$PurchaseHistoryRecordWrapperFromJson(Map json) => purchaseTime: json['purchaseTime'] as int? ?? 0, purchaseToken: json['purchaseToken'] as String? ?? '', signature: json['signature'] as String? ?? '', - skus: json['skus'] != null ? (json['skus'] as List)?.map((item) => item as String)?.toList() ?? [] : [], - // skus: json['skus'] as List? ?? [], + skus: json['skus'] != null + ? (json['skus'] as List)?.map((item) => item as String)?.toList() ?? + [] + : [], originalJson: json['originalJson'] as String? ?? '', developerPayload: json['developerPayload'] as String?, ); diff --git a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart index 30c7187f8444..4f90dccf94f4 100644 --- a/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart +++ b/packages/in_app_purchase/in_app_purchase_android/test/in_app_purchase_android_platform_test.dart @@ -401,7 +401,7 @@ void main() { 'purchasesList': [ { 'orderId': 'orderID1', - 'sku': skuDetails.sku, + 'skus': [skuDetails.sku], 'isAutoRenewing': false, 'packageName': 'package', 'purchaseTime': 1231231231, From a7f7714a84ba99b19357fd6c71b8ecb5ee3f4bbc Mon Sep 17 00:00:00 2001 From: Gary Qian Date: Fri, 8 Jul 2022 01:23:48 -0500 Subject: [PATCH 22/22] Versioning --- .../in_app_purchase/in_app_purchase_android/CHANGELOG.md | 6 ++++++ .../in_app_purchase/in_app_purchase_android/pubspec.yaml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) 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 966df5115e67..2f37f09478c8 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,9 @@ +## 0.2.3 + +* Upgrades Google Play Billing Library to 5.0 +* Migrates APIs to support breaking changes in new Google Play Billing API +* `PurchaseWrapper` and `PurchaseHistoryRecordWrapper` now handles `skus` a list of sku strings. `sku` is deprecated. + ## 0.2.2+8 * Ignores deprecation warnings for upcoming styleFrom button API changes. 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 b1e77666a0b5..db419b8e1aa4 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/plugins/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.2.2+8 +version: 0.2.3 environment: sdk: ">=2.14.0 <3.0.0"