diff --git a/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md b/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md index 87b7fa01ff2..24e5c1a46ea 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md +++ b/packages/in_app_purchase/in_app_purchase_storekit/CHANGELOG.md @@ -1,5 +1,8 @@ -## NEXT +## 0.4.5 +* Adds a new case `.unverified` to enum `SK2ProductPurchaseResult` +* Fixes the StoreKit2 implementation throwing `PlatformException`s instead of returning the corresponding +`SK2ProductPurchaseResult` when a purchase is cancelled / unverified / pending. * Updates minimum supported SDK version to Flutter 3.29/Dart 3.7. ## 0.4.4 diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/InAppPurchasePlugin+StoreKit2.swift b/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/InAppPurchasePlugin+StoreKit2.swift index c559970e8e3..60e571b6f10 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/InAppPurchasePlugin+StoreKit2.swift +++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/InAppPurchasePlugin+StoreKit2.swift @@ -89,32 +89,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: + break @unknown default: fatalError("An unknown StoreKit PurchaseResult has been encountered.") } + completion(.success(result.convertToPigeon())) } catch { completion(.failure(error)) } diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/StoreKit2Translators.swift b/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/StoreKit2Translators.swift index 9be3bb370ca..3266aa3b964 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/StoreKit2Translators.swift +++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/StoreKit2Translators.swift @@ -216,13 +216,11 @@ extension SK2PriceLocaleMessage: Equatable { @available(iOS 15.0, macOS 12.0, *) extension Product.PurchaseResult { func convertToPigeon() -> SK2ProductPurchaseResultMessage { - switch self { - case .success(_): - return SK2ProductPurchaseResultMessage.success - case .userCancelled: - return SK2ProductPurchaseResultMessage.userCancelled - case .pending: - return SK2ProductPurchaseResultMessage.pending + return switch self { + case .success(.verified): .success + case .success(.unverified): .unverified + case .userCancelled: .userCancelled + case .pending: .pending @unknown default: fatalError() } diff --git a/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/sk2_pigeon.g.swift b/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/sk2_pigeon.g.swift index bf07f4e9324..e74412a446e 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/sk2_pigeon.g.swift +++ b/packages/in_app_purchase/in_app_purchase_storekit/darwin/in_app_purchase_storekit/Sources/in_app_purchase_storekit/StoreKit2/sk2_pigeon.g.swift @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v25.3.1), do not edit directly. +// Autogenerated from Pigeon (v25.5.0), do not edit directly. // See also: https://pub.dev/packages/pigeon import Foundation @@ -169,8 +169,9 @@ enum SK2SubscriptionPeriodUnitMessage: Int { enum SK2ProductPurchaseResultMessage: Int { case success = 0 - case userCancelled = 1 - case pending = 2 + case unverified = 1 + case userCancelled = 2 + case pending = 3 } /// Generated class from Pigeon that represents data sent in messages. diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchaseStoreKit2PluginTests.swift b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchaseStoreKit2PluginTests.swift index 7fdbf49febc..bcf073634f9 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchaseStoreKit2PluginTests.swift +++ b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/InAppPurchaseStoreKit2PluginTests.swift @@ -194,7 +194,8 @@ final class InAppPurchase2PluginTests: XCTestCase { let expectation = self.expectation(description: "Purchase request should succeed") plugin.purchase(id: "consumable", options: nil) { result in switch result { - case .success: + case .success(let message): + XCTAssert(message == .success) expectation.fulfill() case .failure(let error): XCTFail("Purchase should NOT fail. Failed with \(error)") diff --git a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/StoreKit2TranslatorTests.swift b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/StoreKit2TranslatorTests.swift index edf936e7347..ad52486284d 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/StoreKit2TranslatorTests.swift +++ b/packages/in_app_purchase/in_app_purchase_storekit/example/shared/RunnerTests/StoreKit2TranslatorTests.swift @@ -105,4 +105,11 @@ final class StoreKit2TranslatorTests: XCTestCase { let pigeonMessage = locale.convertToPigeon XCTAssertEqual(pigeonMessage, productMessage.priceLocale) } + + func testPigeonConversionForPurchaseResult() { + // Unfortunately the .success case is not testable because the Transaction + // type has no visible initializers. + XCTAssertEqual(Product.PurchaseResult.pending.convertToPigeon(), .pending) + XCTAssertEqual(Product.PurchaseResult.userCancelled.convertToPigeon(), .userCancelled) + } } diff --git a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/sk2_pigeon.g.dart b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/sk2_pigeon.g.dart index e875f059905..4d98adc636e 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/sk2_pigeon.g.dart +++ b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/sk2_pigeon.g.dart @@ -1,7 +1,7 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v25.3.1), do not edit directly. +// Autogenerated from Pigeon (v25.5.0), do not edit directly. // See also: https://pub.dev/packages/pigeon // 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 @@ -74,7 +74,12 @@ enum SK2SubscriptionOfferPaymentModeMessage { enum SK2SubscriptionPeriodUnitMessage { day, week, month, year } -enum SK2ProductPurchaseResultMessage { success, userCancelled, pending } +enum SK2ProductPurchaseResultMessage { + success, + unverified, + userCancelled, + pending, +} class SK2SubscriptionOfferMessage { SK2SubscriptionOfferMessage({ diff --git a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_product_wrapper.dart b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_product_wrapper.dart index 9222a2b0e8d..b2d2724fd14 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_product_wrapper.dart +++ b/packages/in_app_purchase/in_app_purchase_storekit/lib/src/store_kit_2_wrappers/sk2_product_wrapper.dart @@ -278,9 +278,12 @@ extension on SK2PriceLocaleMessage { /// 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, @@ -324,14 +327,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, + }; } } diff --git a/packages/in_app_purchase/in_app_purchase_storekit/pigeons/sk2_pigeon.dart b/packages/in_app_purchase/in_app_purchase_storekit/pigeons/sk2_pigeon.dart index 98ca749afb3..1914d2a8604 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/pigeons/sk2_pigeon.dart +++ b/packages/in_app_purchase/in_app_purchase_storekit/pigeons/sk2_pigeon.dart @@ -209,7 +209,12 @@ class SK2ErrorMessage { final Map? userInfo; } -enum SK2ProductPurchaseResultMessage { success, userCancelled, pending } +enum SK2ProductPurchaseResultMessage { + success, + unverified, + userCancelled, + pending, +} @HostApi(dartHostTestHandler: 'TestInAppPurchase2Api') abstract class InAppPurchase2API { diff --git a/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml b/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml index fa934243821..90c00f94e74 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml +++ b/packages/in_app_purchase/in_app_purchase_storekit/pubspec.yaml @@ -2,7 +2,7 @@ name: in_app_purchase_storekit description: An implementation for the iOS and macOS platforms of the Flutter `in_app_purchase` plugin. This uses the StoreKit Framework. repository: https://github.com/flutter/packages/tree/main/packages/in_app_purchase/in_app_purchase_storekit issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+in_app_purchase%22 -version: 0.4.4 +version: 0.4.5 environment: sdk: ^3.7.0 diff --git a/packages/in_app_purchase/in_app_purchase_storekit/test/sk2_test_api.g.dart b/packages/in_app_purchase/in_app_purchase_storekit/test/sk2_test_api.g.dart index 9dcb09e41d0..d867e1998ca 100644 --- a/packages/in_app_purchase/in_app_purchase_storekit/test/sk2_test_api.g.dart +++ b/packages/in_app_purchase/in_app_purchase_storekit/test/sk2_test_api.g.dart @@ -1,16 +1,16 @@ // Copyright 2013 The Flutter Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// Autogenerated from Pigeon (v25.3.1), do not edit directly. +// Autogenerated from Pigeon (v25.5.0), do not edit directly. // See also: https://pub.dev/packages/pigeon // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import, no_leading_underscores_for_local_identifiers // ignore_for_file: avoid_relative_lib_imports import 'dart:async'; import 'dart:typed_data' show Float64List, Int32List, Int64List, Uint8List; - import 'package:flutter/foundation.dart' show ReadBuffer, WriteBuffer; import 'package:flutter/services.dart'; import 'package:flutter_test/flutter_test.dart'; + import 'package:in_app_purchase_storekit/src/sk2_pigeon.g.dart'; class _PigeonCodec extends StandardMessageCodec {