Skip to content

Commit efd33e3

Browse files
authored
[in_app_purchase] Migrate android to Billing to 5.0.0 (flutter#5405)
1 parent bde0d0d commit efd33e3

File tree

13 files changed

+156
-129
lines changed

13 files changed

+156
-129
lines changed

packages/in_app_purchase/in_app_purchase_android/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.2.3
2+
3+
* Upgrades Google Play Billing Library to 5.0
4+
* Migrates APIs to support breaking changes in new Google Play Billing API
5+
* `PurchaseWrapper` and `PurchaseHistoryRecordWrapper` now handles `skus` a list of sku strings. `sku` is deprecated.
6+
17
## 0.2.2+8
28

39
* Ignores deprecation warnings for upcoming styleFrom button API changes.

packages/in_app_purchase/in_app_purchase_android/android/build.gradle

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@ android {
5252
}
5353

5454
dependencies {
55-
implementation 'androidx.annotation:annotation:1.0.0'
56-
implementation 'com.android.billingclient:billing:3.0.2'
55+
implementation 'androidx.annotation:annotation:1.3.0'
56+
implementation 'com.android.billingclient:billing:5.0.0'
5757
testImplementation 'junit:junit:4.13.2'
58-
testImplementation 'org.json:json:20180813'
59-
testImplementation 'org.mockito:mockito-core:3.6.0'
60-
androidTestImplementation 'androidx.test:runner:1.1.1'
61-
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
58+
testImplementation 'org.json:json:20220320'
59+
testImplementation 'org.mockito:mockito-core:4.5.1'
60+
androidTestImplementation 'androidx.test:runner:1.4.0'
61+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
6262
}

packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/InAppPurchasePlugin.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ static final class MethodNames {
3939
static final String ON_PURCHASES_UPDATED =
4040
"PurchasesUpdatedListener#onPurchasesUpdated(int, List<Purchase>)";
4141
static final String QUERY_PURCHASES = "BillingClient#queryPurchases(String)";
42+
static final String QUERY_PURCHASES_ASYNC = "BillingClient#queryPurchasesAsync(String)";
4243
static final String QUERY_PURCHASE_HISTORY_ASYNC =
4344
"BillingClient#queryPurchaseHistoryAsync(String, PurchaseHistoryResponseListener)";
4445
static final String CONSUME_PURCHASE_ASYNC =
@@ -48,6 +49,7 @@ static final class MethodNames {
4849
static final String IS_FEATURE_SUPPORTED = "BillingClient#isFeatureSupported(String)";
4950
static final String LAUNCH_PRICE_CHANGE_CONFIRMATION_FLOW =
5051
"BillingClient#launchPriceChangeConfirmationFlow (Activity, PriceChangeFlowParams, PriceChangeConfirmationListener)";
52+
static final String GET_CONNECTION_STATE = "BillingClient#getConnectionState()";
5153

5254
private MethodNames() {};
5355
}

packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/MethodCallHandlerImpl.java

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
package io.flutter.plugins.inapppurchase;
66

77
import static io.flutter.plugins.inapppurchase.Translator.fromPurchaseHistoryRecordList;
8-
import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesResult;
8+
import static io.flutter.plugins.inapppurchase.Translator.fromPurchasesList;
99
import static io.flutter.plugins.inapppurchase.Translator.fromSkuDetailsList;
1010

1111
import android.app.Activity;
@@ -25,8 +25,12 @@
2525
import com.android.billingclient.api.ConsumeParams;
2626
import com.android.billingclient.api.ConsumeResponseListener;
2727
import com.android.billingclient.api.PriceChangeFlowParams;
28+
import com.android.billingclient.api.Purchase;
2829
import com.android.billingclient.api.PurchaseHistoryRecord;
2930
import com.android.billingclient.api.PurchaseHistoryResponseListener;
31+
import com.android.billingclient.api.PurchasesResponseListener;
32+
import com.android.billingclient.api.QueryPurchaseHistoryParams;
33+
import com.android.billingclient.api.QueryPurchasesParams;
3034
import com.android.billingclient.api.SkuDetails;
3135
import com.android.billingclient.api.SkuDetailsParams;
3236
import com.android.billingclient.api.SkuDetailsResponseListener;
@@ -131,10 +135,14 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) {
131135
: ProrationMode.UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY,
132136
result);
133137
break;
134-
case InAppPurchasePlugin.MethodNames.QUERY_PURCHASES:
135-
queryPurchases((String) call.argument("skuType"), result);
138+
case InAppPurchasePlugin.MethodNames.QUERY_PURCHASES: // Legacy method name.
139+
queryPurchasesAsync((String) call.argument("skuType"), result);
140+
break;
141+
case InAppPurchasePlugin.MethodNames.QUERY_PURCHASES_ASYNC:
142+
queryPurchasesAsync((String) call.argument("skuType"), result);
136143
break;
137144
case InAppPurchasePlugin.MethodNames.QUERY_PURCHASE_HISTORY_ASYNC:
145+
Log.e("flutter", (String) call.argument("skuType"));
138146
queryPurchaseHistoryAsync((String) call.argument("skuType"), result);
139147
break;
140148
case InAppPurchasePlugin.MethodNames.CONSUME_PURCHASE_ASYNC:
@@ -149,6 +157,9 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) {
149157
case InAppPurchasePlugin.MethodNames.LAUNCH_PRICE_CHANGE_CONFIRMATION_FLOW:
150158
launchPriceChangeConfirmationFlow((String) call.argument("sku"), result);
151159
break;
160+
case InAppPurchasePlugin.MethodNames.GET_CONNECTION_STATE:
161+
getConnectionState(result);
162+
break;
152163
default:
153164
result.notImplemented();
154165
}
@@ -174,6 +185,7 @@ private void isReady(MethodChannel.Result result) {
174185
result.success(billingClient.isReady());
175186
}
176187

188+
// TODO(garyq): Migrate to new subscriptions API: https://developer.android.com/google/play/billing/migrate-gpblv5
177189
private void querySkuDetailsAsync(
178190
final String skuType, final List<String> skusList, final MethodChannel.Result result) {
179191
if (billingClientError(result)) {
@@ -208,7 +220,6 @@ private void launchBillingFlow(
208220
if (billingClientError(result)) {
209221
return;
210222
}
211-
212223
SkuDetails skuDetails = cachedSkus.get(sku);
213224
if (skuDetails == null) {
214225
result.error(
@@ -255,12 +266,15 @@ private void launchBillingFlow(
255266
if (obfuscatedProfileId != null && !obfuscatedProfileId.isEmpty()) {
256267
paramsBuilder.setObfuscatedProfileId(obfuscatedProfileId);
257268
}
258-
if (oldSku != null && !oldSku.isEmpty()) {
259-
paramsBuilder.setOldSku(oldSku, purchaseToken);
269+
BillingFlowParams.SubscriptionUpdateParams.Builder subscriptionUpdateParamsBuilder =
270+
BillingFlowParams.SubscriptionUpdateParams.newBuilder();
271+
if (oldSku != null && !oldSku.isEmpty() && purchaseToken != null) {
272+
subscriptionUpdateParamsBuilder.setOldPurchaseToken(purchaseToken);
273+
// The proration mode value has to match one of the following declared in
274+
// https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode
275+
subscriptionUpdateParamsBuilder.setReplaceProrationMode(prorationMode);
276+
paramsBuilder.setSubscriptionUpdateParams(subscriptionUpdateParamsBuilder.build());
260277
}
261-
// The proration mode value has to match one of the following declared in
262-
// https://developer.android.com/reference/com/android/billingclient/api/BillingFlowParams.ProrationMode
263-
paramsBuilder.setReplaceSkusProrationMode(prorationMode);
264278
result.success(
265279
Translator.fromBillingResult(
266280
billingClient.launchBillingFlow(activity, paramsBuilder.build())));
@@ -286,14 +300,30 @@ public void onConsumeResponse(BillingResult billingResult, String outToken) {
286300
billingClient.consumeAsync(params, listener);
287301
}
288302

289-
private void queryPurchases(String skuType, MethodChannel.Result result) {
303+
private void queryPurchasesAsync(String skuType, MethodChannel.Result result) {
290304
if (billingClientError(result)) {
291305
return;
292306
}
293307

294308
// Like in our connect call, consider the billing client responding a "success" here regardless
295309
// of status code.
296-
result.success(fromPurchasesResult(billingClient.queryPurchases(skuType)));
310+
QueryPurchasesParams.Builder paramsBuilder = QueryPurchasesParams.newBuilder();
311+
paramsBuilder.setProductType(skuType);
312+
billingClient.queryPurchasesAsync(
313+
paramsBuilder.build(),
314+
new PurchasesResponseListener() {
315+
@Override
316+
public void onQueryPurchasesResponse(
317+
BillingResult billingResult, List<Purchase> purchasesList) {
318+
final Map<String, Object> serialized = new HashMap<>();
319+
// The response code is no longer passed, as part of billing 4.0, so we pass OK here
320+
// as success is implied by calling this callback.
321+
serialized.put("responseCode", BillingClient.BillingResponseCode.OK);
322+
serialized.put("billingResult", Translator.fromBillingResult(billingResult));
323+
serialized.put("purchaseList", fromPurchasesList(purchasesList));
324+
result.success(serialized);
325+
}
326+
});
297327
}
298328

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

304334
billingClient.queryPurchaseHistoryAsync(
305-
skuType,
335+
QueryPurchaseHistoryParams.newBuilder().setProductType(skuType).build(),
306336
new PurchaseHistoryResponseListener() {
307337
@Override
308338
public void onPurchaseHistoryResponse(
@@ -316,6 +346,15 @@ public void onPurchaseHistoryResponse(
316346
});
317347
}
318348

349+
private void getConnectionState(final MethodChannel.Result result) {
350+
if (billingClientError(result)) {
351+
return;
352+
}
353+
final Map<String, Object> serialized = new HashMap<>();
354+
serialized.put("connectionState", billingClient.getConnectionState());
355+
result.success(serialized);
356+
}
357+
319358
private void startConnection(final int handle, final MethodChannel.Result result) {
320359
if (billingClient == null) {
321360
billingClient = billingClientFactory.createBillingClient(applicationContext, methodChannel);

packages/in_app_purchase/in_app_purchase_android/android/src/main/java/io/flutter/plugins/inapppurchase/Translator.java

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import com.android.billingclient.api.AccountIdentifiers;
99
import com.android.billingclient.api.BillingResult;
1010
import com.android.billingclient.api.Purchase;
11-
import com.android.billingclient.api.Purchase.PurchasesResult;
1211
import com.android.billingclient.api.PurchaseHistoryRecord;
1312
import com.android.billingclient.api.SkuDetails;
1413
import java.util.ArrayList;
@@ -56,17 +55,19 @@ static List<HashMap<String, Object>> fromSkuDetailsList(
5655

5756
static HashMap<String, Object> fromPurchase(Purchase purchase) {
5857
HashMap<String, Object> info = new HashMap<>();
58+
List<String> skus = purchase.getSkus();
5959
info.put("orderId", purchase.getOrderId());
6060
info.put("packageName", purchase.getPackageName());
6161
info.put("purchaseTime", purchase.getPurchaseTime());
6262
info.put("purchaseToken", purchase.getPurchaseToken());
6363
info.put("signature", purchase.getSignature());
64-
info.put("sku", purchase.getSku());
64+
info.put("skus", skus);
6565
info.put("isAutoRenewing", purchase.isAutoRenewing());
6666
info.put("originalJson", purchase.getOriginalJson());
6767
info.put("developerPayload", purchase.getDeveloperPayload());
6868
info.put("isAcknowledged", purchase.isAcknowledged());
6969
info.put("purchaseState", purchase.getPurchaseState());
70+
info.put("quantity", purchase.getQuantity());
7071
AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers();
7172
if (accountIdentifiers != null) {
7273
info.put("obfuscatedAccountId", accountIdentifiers.getObfuscatedAccountId());
@@ -78,12 +79,14 @@ static HashMap<String, Object> fromPurchase(Purchase purchase) {
7879
static HashMap<String, Object> fromPurchaseHistoryRecord(
7980
PurchaseHistoryRecord purchaseHistoryRecord) {
8081
HashMap<String, Object> info = new HashMap<>();
82+
List<String> skus = purchaseHistoryRecord.getSkus();
8183
info.put("purchaseTime", purchaseHistoryRecord.getPurchaseTime());
8284
info.put("purchaseToken", purchaseHistoryRecord.getPurchaseToken());
8385
info.put("signature", purchaseHistoryRecord.getSignature());
84-
info.put("sku", purchaseHistoryRecord.getSku());
86+
info.put("skus", skus);
8587
info.put("developerPayload", purchaseHistoryRecord.getDeveloperPayload());
8688
info.put("originalJson", purchaseHistoryRecord.getOriginalJson());
89+
info.put("quantity", purchaseHistoryRecord.getQuantity());
8790
return info;
8891
}
8992

@@ -112,14 +115,6 @@ static List<HashMap<String, Object>> fromPurchaseHistoryRecordList(
112115
return serialized;
113116
}
114117

115-
static HashMap<String, Object> fromPurchasesResult(PurchasesResult purchasesResult) {
116-
HashMap<String, Object> info = new HashMap<>();
117-
info.put("responseCode", purchasesResult.getResponseCode());
118-
info.put("billingResult", fromBillingResult(purchasesResult.getBillingResult()));
119-
info.put("purchasesList", fromPurchasesList(purchasesResult.getPurchasesList()));
120-
return info;
121-
}
122-
123118
static HashMap<String, Object> fromBillingResult(BillingResult billingResult) {
124119
HashMap<String, Object> info = new HashMap<>();
125120
info.put("responseCode", billingResult.getResponseCode());

0 commit comments

Comments
 (0)