I am trying to setup an in-app purchase for a non-consumable product with StoreKit 2. If you look at the App Store Connect / Xcode configuration file for in-app purchase there are 43 error conditions that Apple suggest testing before submitting an app for review. The problem is that all online sample code (including Apple’s) never show how to setup the code required to support these errors.
Specifically I am seeking help with load product errors. Under Apple’s discussion of products(for:) it says: If any identifiers are invalid or the App Store can’t find them, the App Store excludes them from the return value. The products(for:) function can throw a StoreKitError for system-related errors.
In my testing of load product errors I get an empty screen with a spinning wheel (progressView()) for all of these errors.
I am currently getting all kinds of errors in my product catch block switch statement such as Type '[Product]' has no member 'systemError'. It doesn't seem to recognize my StoreKitError enum. In the code below I'm not showing all of my StoreModel. I would be glad to show more if requested.
@MainActor final class StoreModel: ObservableObject {
enum StoreKitError {
case networkError(URLError)
case systemError(any Error)
case userCancelled
case notAvailableInStorefront
case notEntitled
case unknown
}
public enum PurchaseFinishedAction {
case dismissStore
case noAction
case displayError
}
func fetchProducts() async throws -> PurchaseFinishedAction {
let action: PurchaseFinishedAction
do {
products = try await Product.products(
for: productIDs)
} catch {
switch products {
case .networkError(URLError):
action = .displayError
case .systemError(any Error):
action = .displayError
case .userCancelled:
action = .noAction
case .notAvailableInStorefront:
action = .displayError
case .notEntitled:
action = .displayError
case .product.unknown:
action = .displayError
}
}
return action
}
Note, I'm not familliar with StoreKit
, but this example code compiles for me.
Note also StoreKit
has already a StoreKitError
no need to redeclare them,
not sure about PurchaseFinishedAction
@MainActor final class StoreModel: ObservableObject {
@Published var products: [Product] = [] // <--- here
public enum PurchaseFinishedAction {
case dismissStore
case noAction
case displayError
case noStoreKitError // <--- here
}
func fetchProducts() async throws -> PurchaseFinishedAction {
var action = PurchaseFinishedAction.noStoreKitError // <--- here
do {
products = try await Product.products(for: ["com.example.productA"]) // productIDs
} catch {
if let err = error as? StoreKitError { // <--- here
switch err {
case .networkError(let urlError):
action = .displayError
case .systemError(let sysError):
action = .displayError
case .userCancelled:
action = .noAction
case .notAvailableInStorefront:
action = .displayError
case .notEntitled:
action = .displayError
case .unknown:
action = .displayError
default:
action = .displayError // <--- here, todo
}
}
}
return action
}
}