[in_app_purchase]IAP/android add cancel status (#4095)
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 c504bd7..78aa8db 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,8 @@
+## 0.2.0
+
+* BREAKING CHANGE : Refactor to handle new `PurchaseStatus` named `canceled`. This means developers
+ can distinguish between an error and user cancellation.
+
## 0.1.6
* Require Dart SDK >= 2.14.
diff --git a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart
index f71132a..7deec6e 100644
--- a/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart
+++ b/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart
@@ -260,8 +260,12 @@
}
final List<Future<PurchaseDetails>> purchases =
resultWrapper.purchasesList.map((PurchaseWrapper purchase) {
- return _maybeAutoConsumePurchase(
- GooglePlayPurchaseDetails.fromPurchase(purchase)..error = error);
+ final GooglePlayPurchaseDetails googlePlayPurchaseDetails =
+ GooglePlayPurchaseDetails.fromPurchase(purchase)..error = error;
+ if (resultWrapper.responseCode == BillingResponse.userCanceled) {
+ googlePlayPurchaseDetails.status = PurchaseStatus.canceled;
+ }
+ return _maybeAutoConsumePurchase(googlePlayPurchaseDetails);
}).toList();
if (purchases.isNotEmpty) {
return Future.wait(purchases);
@@ -270,7 +274,9 @@
PurchaseDetails(
purchaseID: '',
productID: '',
- status: PurchaseStatus.error,
+ status: resultWrapper.responseCode == BillingResponse.userCanceled
+ ? PurchaseStatus.canceled
+ : PurchaseStatus.error,
transactionDate: null,
verificationData: PurchaseVerificationData(
localVerificationData: '',
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 fef2dab..7d5c610 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 @@
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/master/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.1.6
+version: 0.2.0
environment:
sdk: ">=2.14.0 <3.0.0"
@@ -20,7 +20,7 @@
collection: ^1.15.0
flutter:
sdk: flutter
- in_app_purchase_platform_interface: ^1.1.0
+ in_app_purchase_platform_interface: ^1.3.0
json_annotation: ^4.3.0
meta: ^1.3.0
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 bd70489..12cca69 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
@@ -616,6 +616,74 @@
purchaseParam: purchaseParam, autoConsume: false);
expect(null, await consumeCompleter.future);
});
+
+ test(
+ 'should get canceled purchase status when response code is BillingResponse.userCanceled',
+ () async {
+ final SkuDetailsWrapper skuDetails = dummySkuDetails;
+ final String accountId = "hashedAccountId";
+ const String debugMessage = 'dummy message';
+ final BillingResponse sentCode = BillingResponse.userCanceled;
+ final BillingResultWrapper expectedBillingResult = BillingResultWrapper(
+ responseCode: sentCode, debugMessage: debugMessage);
+ stubPlatform.addResponse(
+ name: launchMethodName,
+ value: buildBillingResultMap(expectedBillingResult),
+ additionalStepBeforeReturn: (_) {
+ // Mock java update purchase callback.
+ MethodCall call = MethodCall(kOnPurchasesUpdated, {
+ 'billingResult': buildBillingResultMap(expectedBillingResult),
+ 'responseCode': BillingResponseConverter().toJson(sentCode),
+ 'purchasesList': [
+ {
+ 'orderId': 'orderID1',
+ 'sku': skuDetails.sku,
+ 'isAutoRenewing': false,
+ 'packageName': "package",
+ 'purchaseTime': 1231231231,
+ 'purchaseToken': "token",
+ 'signature': 'sign',
+ 'originalJson': 'json',
+ 'developerPayload': 'dummy payload',
+ 'isAcknowledged': true,
+ 'purchaseState': 1,
+ }
+ ]
+ });
+ iapAndroidPlatform.billingClient.callHandler(call);
+ });
+ Completer consumeCompleter = Completer();
+ // adding call back for consume purchase
+ final BillingResponse expectedCode = BillingResponse.userCanceled;
+ final BillingResultWrapper expectedBillingResultForConsume =
+ BillingResultWrapper(
+ responseCode: expectedCode, debugMessage: debugMessage);
+ stubPlatform.addResponse(
+ name: consumeMethodName,
+ value: buildBillingResultMap(expectedBillingResultForConsume),
+ additionalStepBeforeReturn: (dynamic args) {
+ String purchaseToken = args['purchaseToken'];
+ consumeCompleter.complete(purchaseToken);
+ });
+
+ Completer completer = Completer();
+ PurchaseDetails purchaseDetails;
+ Stream purchaseStream = iapAndroidPlatform.purchaseStream;
+ late StreamSubscription subscription;
+ subscription = purchaseStream.listen((_) {
+ purchaseDetails = _.first;
+ completer.complete(purchaseDetails);
+ subscription.cancel();
+ }, onDone: () {});
+ final GooglePlayPurchaseParam purchaseParam = GooglePlayPurchaseParam(
+ productDetails: GooglePlayProductDetails.fromSkuDetails(skuDetails),
+ applicationUserName: accountId);
+ await iapAndroidPlatform.buyConsumable(purchaseParam: purchaseParam);
+
+ // Verify that the result has an error for the failed consumption
+ GooglePlayPurchaseDetails result = await completer.future;
+ expect(result.status, PurchaseStatus.canceled);
+ });
});
group('complete purchase', () {