Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

[in_app_purchase] Migrate to Billing to 5.0.0 #5405

Merged
merged 22 commits into from
Jul 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.mockito:mockito-core:3.6.0'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
testImplementation 'org.json:json:20220320'
testImplementation 'org.mockito:mockito-core:4.5.1'
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ static final class MethodNames {
static final String ON_PURCHASES_UPDATED =
"PurchasesUpdatedListener#onPurchasesUpdated(int, List<Purchase>)";
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)";
static final String CONSUME_PURCHASE_ASYNC =
Expand All @@ -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() {};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -25,8 +25,12 @@
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.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;
Expand Down Expand Up @@ -131,10 +135,14 @@ 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:
Log.e("flutter", (String) call.argument("skuType"));
queryPurchaseHistoryAsync((String) call.argument("skuType"), result);
break;
case InAppPurchasePlugin.MethodNames.CONSUME_PURCHASE_ASYNC:
Expand All @@ -149,6 +157,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(result);
break;
default:
result.notImplemented();
}
Expand All @@ -174,6 +185,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<String> skusList, final MethodChannel.Result result) {
if (billingClientError(result)) {
Expand Down Expand Up @@ -208,7 +220,6 @@ private void launchBillingFlow(
if (billingClientError(result)) {
return;
}

SkuDetails skuDetails = cachedSkus.get(sku);
if (skuDetails == null) {
result.error(
Expand Down Expand Up @@ -255,12 +266,15 @@ private void launchBillingFlow(
if (obfuscatedProfileId != null && !obfuscatedProfileId.isEmpty()) {
paramsBuilder.setObfuscatedProfileId(obfuscatedProfileId);
}
if (oldSku != null && !oldSku.isEmpty()) {
paramsBuilder.setOldSku(oldSku, 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.setReplaceProrationMode(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
paramsBuilder.setReplaceSkusProrationMode(prorationMode);
result.success(
Translator.fromBillingResult(
billingClient.launchBillingFlow(activity, paramsBuilder.build())));
Expand All @@ -286,14 +300,30 @@ 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)));
QueryPurchasesParams.Builder paramsBuilder = QueryPurchasesParams.newBuilder();
paramsBuilder.setProductType(skuType);
billingClient.queryPurchasesAsync(
paramsBuilder.build(),
new PurchasesResponseListener() {
@Override
public void onQueryPurchasesResponse(
BillingResult billingResult, List<Purchase> purchasesList) {
final Map<String, Object> 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);
}
});
}

private void queryPurchaseHistoryAsync(String skuType, final MethodChannel.Result result) {
Expand All @@ -302,7 +332,7 @@ private void queryPurchaseHistoryAsync(String skuType, final MethodChannel.Resul
}

billingClient.queryPurchaseHistoryAsync(
skuType,
QueryPurchaseHistoryParams.newBuilder().setProductType(skuType).build(),
new PurchaseHistoryResponseListener() {
@Override
public void onPurchaseHistoryResponse(
Expand All @@ -316,6 +346,15 @@ public void onPurchaseHistoryResponse(
});
}

private void getConnectionState(final MethodChannel.Result result) {
if (billingClientError(result)) {
return;
}
final Map<String, Object> 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -56,17 +55,19 @@ static List<HashMap<String, Object>> fromSkuDetailsList(

static HashMap<String, Object> fromPurchase(Purchase purchase) {
HashMap<String, Object> info = new HashMap<>();
List<String> 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.getSku());
info.put("skus", skus);
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());
Expand All @@ -78,12 +79,14 @@ static HashMap<String, Object> fromPurchase(Purchase purchase) {
static HashMap<String, Object> fromPurchaseHistoryRecord(
PurchaseHistoryRecord purchaseHistoryRecord) {
HashMap<String, Object> info = new HashMap<>();
List<String> skus = purchaseHistoryRecord.getSkus();
info.put("purchaseTime", purchaseHistoryRecord.getPurchaseTime());
info.put("purchaseToken", purchaseHistoryRecord.getPurchaseToken());
info.put("signature", purchaseHistoryRecord.getSignature());
info.put("sku", purchaseHistoryRecord.getSku());
info.put("skus", skus);
info.put("developerPayload", purchaseHistoryRecord.getDeveloperPayload());
info.put("originalJson", purchaseHistoryRecord.getOriginalJson());
info.put("quantity", purchaseHistoryRecord.getQuantity());
return info;
}

Expand Down Expand Up @@ -112,14 +115,6 @@ static List<HashMap<String, Object>> fromPurchaseHistoryRecordList(
return serialized;
}

static HashMap<String, Object> fromPurchasesResult(PurchasesResult purchasesResult) {
HashMap<String, Object> info = new HashMap<>();
info.put("responseCode", purchasesResult.getResponseCode());
info.put("billingResult", fromBillingResult(purchasesResult.getBillingResult()));
info.put("purchasesList", fromPurchasesList(purchasesResult.getPurchasesList()));
return info;
}

static HashMap<String, Object> fromBillingResult(BillingResult billingResult) {
HashMap<String, Object> info = new HashMap<>();
info.put("responseCode", billingResult.getResponseCode());
Expand Down
Loading