-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[In_app_purchase_storekit] Do not throw PigeonError when a transaction is pending / cancelled / unverified #9627
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 3 commits
57d374d
80e704b
a163718
45cf639
c9a6040
11f3754
846ce4a
5efc7b4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -86,32 +86,14 @@ extension InAppPurchasePlugin: InAppPurchase2API { | |
|
|
||
| switch result { | ||
| case .success(let verification): | ||
| switch verification { | ||
| case .verified(let transaction): | ||
| self.sendTransactionUpdate( | ||
| transaction: transaction, receipt: verification.jwsRepresentation) | ||
| completion(.success(result.convertToPigeon())) | ||
| case .unverified(_, let error): | ||
| completion(.failure(error)) | ||
| } | ||
| case .pending: | ||
| completion( | ||
| .failure( | ||
| PigeonError( | ||
| code: "storekit2_purchase_pending", | ||
| message: | ||
| "This transaction is still pending and but may complete in the future. If it completes, it will be delivered via `purchaseStream`", | ||
| details: "Product ID : \(id)"))) | ||
| case .userCancelled: | ||
| completion( | ||
| .failure( | ||
| PigeonError( | ||
| code: "storekit2_purchase_cancelled", | ||
| message: "This transaction has been cancelled by the user.", | ||
| details: "Product ID : \(id)"))) | ||
| sendTransactionUpdate( | ||
| transaction: verification.unsafePayloadValue, receipt: verification.jwsRepresentation) | ||
| case .pending, .userCancelled: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both the pending and userCancelled states should be communicated to the upper layer via either the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| break | ||
| @unknown default: | ||
| fatalError("An unknown StoreKit PurchaseResult has been encountered.") | ||
| } | ||
| completion(.success(result.convertToPigeon())) | ||
| } catch { | ||
| completion(.failure(error)) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,7 +22,7 @@ enum SK2ProductType { | |
| nonRenewable, | ||
|
|
||
| /// An auto-renewable subscription. | ||
| autoRenewable; | ||
| autoRenewable, | ||
| } | ||
|
|
||
| extension on SK2ProductTypeMessage { | ||
|
|
@@ -119,12 +119,13 @@ class SK2SubscriptionOffer { | |
| extension on SK2SubscriptionOfferMessage { | ||
| SK2SubscriptionOffer convertFromPigeon() { | ||
| return SK2SubscriptionOffer( | ||
| id: id, | ||
| price: price, | ||
| type: type.convertFromPigeon(), | ||
| period: period.convertFromPigeon(), | ||
| periodCount: periodCount, | ||
| paymentMode: paymentMode.convertFromPigeon()); | ||
| id: id, | ||
| price: price, | ||
| type: type.convertFromPigeon(), | ||
| period: period.convertFromPigeon(), | ||
| periodCount: periodCount, | ||
| paymentMode: paymentMode.convertFromPigeon(), | ||
| ); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -196,7 +197,7 @@ enum SK2SubscriptionPeriodUnit { | |
| month, | ||
|
|
||
| /// A subscription period unit of a year. | ||
| year | ||
| year, | ||
| } | ||
|
|
||
| extension on SK2SubscriptionPeriodUnitMessage { | ||
|
|
@@ -224,7 +225,7 @@ enum SK2SubscriptionOfferPaymentMode { | |
| payUpFront, | ||
|
|
||
| /// A payment mode of a product discount that indicates a free trial offer. | ||
| freeTrial; | ||
| freeTrial, | ||
| } | ||
|
|
||
| extension on SK2SubscriptionOfferPaymentModeMessage { | ||
|
|
@@ -255,28 +256,35 @@ class SK2PriceLocale { | |
| /// Convert this instance of [SK2PriceLocale] to [SK2PriceLocaleMessage] | ||
| SK2PriceLocaleMessage convertToPigeon() { | ||
| return SK2PriceLocaleMessage( | ||
| currencyCode: currencyCode, currencySymbol: currencySymbol); | ||
| currencyCode: currencyCode, | ||
| currencySymbol: currencySymbol, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| extension on SK2PriceLocaleMessage { | ||
| SK2PriceLocale convertFromPigeon() { | ||
| return SK2PriceLocale( | ||
| currencyCode: currencyCode, currencySymbol: currencySymbol); | ||
| currencyCode: currencyCode, | ||
| currencySymbol: currencySymbol, | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| /// Wrapper around [PurchaseResult] | ||
| /// https://developer.apple.com/documentation/storekit/product/purchaseresult | ||
| enum SK2ProductPurchaseResult { | ||
| /// The purchase succeeded and results in a transaction. | ||
| /// The purchase succeeded and results in a transaction signed by the App Store. | ||
| success, | ||
|
|
||
| /// The purchase succeeded but the transation could not be verified. | ||
| unverified, | ||
|
|
||
| /// The user canceled the purchase. | ||
| userCancelled, | ||
|
|
||
| /// The purchase is pending, and requires action from the customer. | ||
| pending | ||
| pending, | ||
| } | ||
|
|
||
| /// Wrapper around [PurchaseOption] | ||
|
|
@@ -315,14 +323,16 @@ class SK2ProductPurchaseOptions { | |
|
|
||
| extension on SK2ProductPurchaseResultMessage { | ||
| SK2ProductPurchaseResult convertFromPigeon() { | ||
| switch (this) { | ||
| case SK2ProductPurchaseResultMessage.success: | ||
| return SK2ProductPurchaseResult.success; | ||
| case SK2ProductPurchaseResultMessage.userCancelled: | ||
| return SK2ProductPurchaseResult.userCancelled; | ||
| case SK2ProductPurchaseResultMessage.pending: | ||
| return SK2ProductPurchaseResult.pending; | ||
| } | ||
| return switch (this) { | ||
| SK2ProductPurchaseResultMessage.success => | ||
| SK2ProductPurchaseResult.success, | ||
| SK2ProductPurchaseResultMessage.userCancelled => | ||
| SK2ProductPurchaseResult.userCancelled, | ||
| SK2ProductPurchaseResultMessage.pending => | ||
| SK2ProductPurchaseResult.pending, | ||
| SK2ProductPurchaseResultMessage.unverified => | ||
| SK2ProductPurchaseResult.unverified, | ||
| }; | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -371,8 +381,9 @@ class SK2Product { | |
| /// If any of the identifiers are invalid or can't be found, they are excluded | ||
| /// from the returned list. | ||
| static Future<List<SK2Product>> products(List<String> identifiers) async { | ||
| final List<SK2ProductMessage?> productsMsg = | ||
| await _hostApi.products(identifiers); | ||
| final List<SK2ProductMessage?> productsMsg = await _hostApi.products( | ||
| identifiers, | ||
| ); | ||
| if (productsMsg.isEmpty && identifiers.isNotEmpty) { | ||
| throw PlatformException( | ||
| code: 'storekit_no_response', | ||
|
|
@@ -389,8 +400,10 @@ class SK2Product { | |
| /// Wrapper for StoreKit's [Product.purchase] | ||
| /// https://developer.apple.com/documentation/storekit/product/3791971-purchase | ||
| /// Initiates a purchase for the product with the App Store and displays the confirmation sheet. | ||
| static Future<SK2ProductPurchaseResult> purchase(String id, | ||
| {SK2ProductPurchaseOptions? options}) async { | ||
| static Future<SK2ProductPurchaseResult> purchase( | ||
| String id, { | ||
| SK2ProductPurchaseOptions? options, | ||
| }) async { | ||
| SK2ProductPurchaseResultMessage result; | ||
| if (options != null) { | ||
| result = await _hostApi.purchase(id, options: options.convertToPigeon()); | ||
|
|
@@ -402,12 +415,8 @@ class SK2Product { | |
|
|
||
| /// Checks if the user is eligible for an introductory offer. | ||
| /// The product must be an auto-renewable subscription. | ||
| static Future<bool> isIntroductoryOfferEligible( | ||
| String productId, | ||
| ) async { | ||
| final bool result = await _hostApi.isIntroductoryOfferEligible( | ||
| productId, | ||
| ); | ||
| static Future<bool> isIntroductoryOfferEligible(String productId) async { | ||
| final bool result = await _hostApi.isIntroductoryOfferEligible(productId); | ||
|
|
||
|
Comment on lines
418
to
420
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function can be simplified for improved conciseness. The intermediate
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can eliminate the unnecessary
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the style guide might be wrong now that we use dart format. |
||
| return result; | ||
| } | ||
|
|
@@ -428,26 +437,28 @@ class SK2Product { | |
| /// Converts this instance of [SK2Product] to it's pigeon representation [SK2ProductMessage] | ||
| SK2ProductMessage convertToPigeon() { | ||
| return SK2ProductMessage( | ||
| id: id, | ||
| displayName: displayName, | ||
| description: description, | ||
| price: price, | ||
| displayPrice: displayPrice, | ||
| type: type.convertToPigeon(), | ||
| priceLocale: priceLocale.convertToPigeon()); | ||
| id: id, | ||
| displayName: displayName, | ||
| description: description, | ||
| price: price, | ||
| displayPrice: displayPrice, | ||
| type: type.convertToPigeon(), | ||
| priceLocale: priceLocale.convertToPigeon(), | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| extension on SK2ProductMessage { | ||
| SK2Product convertFromPigeon() { | ||
| return SK2Product( | ||
| id: id, | ||
| displayName: displayName, | ||
| displayPrice: displayPrice, | ||
| price: price, | ||
| description: description, | ||
| type: type.convertFromPigeon(), | ||
| subscription: subscription?.convertFromPigeon(), | ||
| priceLocale: priceLocale.convertFromPigeon()); | ||
| id: id, | ||
| displayName: displayName, | ||
| displayPrice: displayPrice, | ||
| price: price, | ||
| description: description, | ||
| type: type.convertFromPigeon(), | ||
| subscription: subscription?.convertFromPigeon(), | ||
| priceLocale: priceLocale.convertFromPigeon(), | ||
| ); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the documentation
unsafeseems to mean that the transaction is potentially unverified.