Skip to content

Commit c7a25fa

Browse files
[In_app_purchase_storekit] Do not throw PigeonError when a transaction is pending / cancelled / unverified (#9627)
Fixes flutter/flutter#169524 ## Pre-Review Checklist [^1]: Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling.
1 parent b2530f5 commit c7a25fa

File tree

11 files changed

+59
-49
lines changed

11 files changed

+59
-49
lines changed

packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 0.4.6
2+
3+
* Adds a new case `.unverified` to enum `SK2ProductPurchaseResult`
4+
* Fixes the StoreKit2 implementation throwing `PlatformException`s instead of returning the corresponding
5+
`SK2ProductPurchaseResult` when a purchase is cancelled / unverified / pending.
6+
17
## 0.4.5
28

39
* Makes `SKError.userInfo` key non-nullable to comply with json serialization requirements.

packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/InAppPurchasePlugin+StoreKit2.swift

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -89,32 +89,14 @@ extension InAppPurchasePlugin: InAppPurchase2API {
8989

9090
switch result {
9191
case .success(let verification):
92-
switch verification {
93-
case .verified(let transaction):
94-
self.sendTransactionUpdate(
95-
transaction: transaction, receipt: verification.jwsRepresentation)
96-
completion(.success(result.convertToPigeon()))
97-
case .unverified(_, let error):
98-
completion(.failure(error))
99-
}
100-
case .pending:
101-
completion(
102-
.failure(
103-
PigeonError(
104-
code: "storekit2_purchase_pending",
105-
message:
106-
"This transaction is still pending and but may complete in the future. If it completes, it will be delivered via `purchaseStream`",
107-
details: "Product ID : \(id)")))
108-
case .userCancelled:
109-
completion(
110-
.failure(
111-
PigeonError(
112-
code: "storekit2_purchase_cancelled",
113-
message: "This transaction has been cancelled by the user.",
114-
details: "Product ID : \(id)")))
92+
sendTransactionUpdate(
93+
transaction: verification.unsafePayloadValue, receipt: verification.jwsRepresentation)
94+
case .pending, .userCancelled:
95+
break
11596
@unknown default:
11697
fatalError("An unknown StoreKit PurchaseResult has been encountered.")
11798
}
99+
completion(.success(result.convertToPigeon()))
118100
} catch {
119101
completion(.failure(error))
120102
}

packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/StoreKit2Translators.swift

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -216,13 +216,11 @@ extension SK2PriceLocaleMessage: Equatable {
216216
@available(iOS 15.0, macOS 12.0, *)
217217
extension Product.PurchaseResult {
218218
func convertToPigeon() -> SK2ProductPurchaseResultMessage {
219-
switch self {
220-
case .success(_):
221-
return SK2ProductPurchaseResultMessage.success
222-
case .userCancelled:
223-
return SK2ProductPurchaseResultMessage.userCancelled
224-
case .pending:
225-
return SK2ProductPurchaseResultMessage.pending
219+
return switch self {
220+
case .success(.verified): .success
221+
case .success(.unverified): .unverified
222+
case .userCancelled: .userCancelled
223+
case .pending: .pending
226224
@unknown default:
227225
fatalError()
228226
}

packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/sk2_pigeon.g.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2013 The Flutter Authors
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
4-
// Autogenerated from Pigeon (v25.3.1), do not edit directly.
4+
// Autogenerated from Pigeon (v25.5.0), do not edit directly.
55
// See also: https://pub.dev/packages/pigeon
66

77
import Foundation
@@ -169,8 +169,9 @@ enum SK2SubscriptionPeriodUnitMessage: Int {
169169

170170
enum SK2ProductPurchaseResultMessage: Int {
171171
case success = 0
172-
case userCancelled = 1
173-
case pending = 2
172+
case unverified = 1
173+
case userCancelled = 2
174+
case pending = 3
174175
}
175176

176177
/// Generated class from Pigeon that represents data sent in messages.

packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchaseStoreKit2PluginTests.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,8 @@ final class InAppPurchase2PluginTests: XCTestCase {
194194
let expectation = self.expectation(description: "Purchase request should succeed")
195195
plugin.purchase(id: "consumable", options: nil) { result in
196196
switch result {
197-
case .success:
197+
case .success(let message):
198+
XCTAssert(message == .success)
198199
expectation.fulfill()
199200
case .failure(let error):
200201
XCTFail("Purchase should NOT fail. Failed with \(error)")

packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/StoreKit2TranslatorTests.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,4 +105,11 @@ final class StoreKit2TranslatorTests: XCTestCase {
105105
let pigeonMessage = locale.convertToPigeon
106106
XCTAssertEqual(pigeonMessage, productMessage.priceLocale)
107107
}
108+
109+
func testPigeonConversionForPurchaseResult() {
110+
// Unfortunately the .success case is not testable because the Transaction
111+
// type has no visible initializers.
112+
XCTAssertEqual(Product.PurchaseResult.pending.convertToPigeon(), .pending)
113+
XCTAssertEqual(Product.PurchaseResult.userCancelled.convertToPigeon(), .userCancelled)
114+
}
108115
}

packages/in_app_purchase/in_app_purchase_storekit/lib/src/sk2_pigeon.g.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2013 The Flutter Authors
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
4-
// Autogenerated from Pigeon (v25.3.1), do not edit directly.
4+
// Autogenerated from Pigeon (v25.5.0), do not edit directly.
55
// See also: https://pub.dev/packages/pigeon
66
// ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import, no_leading_underscores_for_local_identifiers
77

@@ -74,7 +74,12 @@ enum SK2SubscriptionOfferPaymentModeMessage {
7474

7575
enum SK2SubscriptionPeriodUnitMessage { day, week, month, year }
7676

77-
enum SK2ProductPurchaseResultMessage { success, userCancelled, pending }
77+
enum SK2ProductPurchaseResultMessage {
78+
success,
79+
unverified,
80+
userCancelled,
81+
pending,
82+
}
7883

7984
class SK2SubscriptionOfferMessage {
8085
SK2SubscriptionOfferMessage({

packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_product_wrapper.dart

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -274,9 +274,12 @@ extension on SK2PriceLocaleMessage {
274274
/// Wrapper around [PurchaseResult]
275275
/// https://developer.apple.com/documentation/storekit/product/purchaseresult
276276
enum SK2ProductPurchaseResult {
277-
/// The purchase succeeded and results in a transaction.
277+
/// The purchase succeeded and results in a transaction signed by the App Store.
278278
success,
279279

280+
/// The purchase succeeded but the transation could not be verified.
281+
unverified,
282+
280283
/// The user canceled the purchase.
281284
userCancelled,
282285

@@ -320,14 +323,16 @@ class SK2ProductPurchaseOptions {
320323

321324
extension on SK2ProductPurchaseResultMessage {
322325
SK2ProductPurchaseResult convertFromPigeon() {
323-
switch (this) {
324-
case SK2ProductPurchaseResultMessage.success:
325-
return SK2ProductPurchaseResult.success;
326-
case SK2ProductPurchaseResultMessage.userCancelled:
327-
return SK2ProductPurchaseResult.userCancelled;
328-
case SK2ProductPurchaseResultMessage.pending:
329-
return SK2ProductPurchaseResult.pending;
330-
}
326+
return switch (this) {
327+
SK2ProductPurchaseResultMessage.success =>
328+
SK2ProductPurchaseResult.success,
329+
SK2ProductPurchaseResultMessage.userCancelled =>
330+
SK2ProductPurchaseResult.userCancelled,
331+
SK2ProductPurchaseResultMessage.pending =>
332+
SK2ProductPurchaseResult.pending,
333+
SK2ProductPurchaseResultMessage.unverified =>
334+
SK2ProductPurchaseResult.unverified,
335+
};
331336
}
332337
}
333338

packages/in_app_purchase/in_app_purchase_storekit/pigeons/sk2_pigeon.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,12 @@ class SK2ErrorMessage {
209209
final Map<String, Object>? userInfo;
210210
}
211211

212-
enum SK2ProductPurchaseResultMessage { success, userCancelled, pending }
212+
enum SK2ProductPurchaseResultMessage {
213+
success,
214+
unverified,
215+
userCancelled,
216+
pending,
217+
}
213218

214219
@HostApi(dartHostTestHandler: 'TestInAppPurchase2Api')
215220
abstract class InAppPurchase2API {

packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: in_app_purchase_storekit
22
description: An implementation for the iOS and macOS platforms of the Flutter `in_app_purchase` plugin. This uses the StoreKit Framework.
33
repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_storekit
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22
5-
version: 0.4.5
5+
version: 0.4.6
66

77
environment:
88
sdk: ^3.9.0

0 commit comments

Comments
 (0)