fix: retry StoreKit tip product lookup
This commit is contained in:
@@ -721,7 +721,7 @@ final class TipStore: ObservableObject {
|
|||||||
// (or restored transactions) are picked up.
|
// (or restored transactions) are picked up.
|
||||||
do {
|
do {
|
||||||
let fetched = try await Product.products(for: Self.tiers.map(\.id))
|
let fetched = try await Product.products(for: Self.tiers.map(\.id))
|
||||||
products = Dictionary(uniqueKeysWithValues: fetched.map { ($0.id, $0) })
|
merge(fetched)
|
||||||
} catch {
|
} catch {
|
||||||
// No products yet (sideloaded build) — the buttons still show the
|
// No products yet (sideloaded build) — the buttons still show the
|
||||||
// intended prices and report purchase attempts gracefully.
|
// intended prices and report purchase attempts gracefully.
|
||||||
@@ -729,24 +729,37 @@ final class TipStore: ObservableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func merge(_ fetched: [Product]) {
|
||||||
|
products.merge(Dictionary(uniqueKeysWithValues: fetched.map { ($0.id, $0) })) { _, new in new }
|
||||||
|
}
|
||||||
|
|
||||||
|
private func product(for tier: TipTier) async throws -> Product? {
|
||||||
|
if let product = products[tier.id] { return product }
|
||||||
|
|
||||||
|
// TestFlight/App Store Connect product availability can lag the Settings
|
||||||
|
// onAppear load. Re-query the tapped tier before falling back so a newly
|
||||||
|
// approved IAP opens the system purchase sheet instead of showing stale
|
||||||
|
// "not available" copy.
|
||||||
|
let fetched = try await Product.products(for: [tier.id])
|
||||||
|
merge(fetched)
|
||||||
|
return fetched.first { $0.id == tier.id }
|
||||||
|
}
|
||||||
|
|
||||||
func purchase(_ tier: TipTier) async {
|
func purchase(_ tier: TipTier) async {
|
||||||
guard !purchaseInProgress else { return }
|
guard !purchaseInProgress else { return }
|
||||||
purchaseInProgress = true
|
purchaseInProgress = true
|
||||||
defer { purchaseInProgress = false }
|
defer { purchaseInProgress = false }
|
||||||
|
|
||||||
// If the product hasn't loaded (e.g. not configured in App Store
|
do {
|
||||||
// Connect yet), still allow the attempt so the user sees a clear
|
guard let product = try await product(for: tier) else {
|
||||||
// outcome rather than a dead button.
|
|
||||||
guard let product = products[tier.id] else {
|
|
||||||
showOutcome(
|
showOutcome(
|
||||||
NSLocalizedString("The tip isn't available in this build yet — check back after an App Store release.", comment: ""),
|
NSLocalizedString("This tip isn't available from the App Store yet. Please try again shortly.", comment: ""),
|
||||||
icon: "info.circle.fill",
|
icon: "info.circle.fill",
|
||||||
tint: Color(.secondaryLabel)
|
tint: Color(.secondaryLabel)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
|
||||||
let result = try await product.purchase()
|
let result = try await product.purchase()
|
||||||
switch result {
|
switch result {
|
||||||
case .success(let verification):
|
case .success(let verification):
|
||||||
|
|||||||
Reference in New Issue
Block a user