Skip to content

Commit c79669d

Browse files
authored
Merge pull request #8113 from woocommerce/issue/8112-improve-error-reporting
[In-app Purchases] Improve error reporting
2 parents 8af7cdd + 8494efb commit c79669d

File tree

2 files changed

+98
-7
lines changed

2 files changed

+98
-7
lines changed

WooCommerce/Classes/ViewRelated/InAppPurchases/InAppPurchasesDebugView.swift

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ struct InAppPurchasesDebugView: View {
1010
@State var entitledProductIDs: Set<String> = []
1111
@State var inAppPurchasesAreSupported = true
1212
@State var isPurchasing = false
13+
@State private var purchaseError: PurchaseError? {
14+
didSet {
15+
presentAlert = purchaseError != nil
16+
}
17+
}
18+
@State var presentAlert = false
1319

1420
var body: some View {
1521
List {
@@ -30,11 +36,16 @@ struct InAppPurchasesDebugView: View {
3036
Button(entitledProductIDs.contains(product.id) ? "Entitled: \(product.description)" : product.description) {
3137
Task {
3238
isPurchasing = true
33-
try? await inAppPurchasesForWPComPlansManager.purchaseProduct(with: product.id, for: siteID)
39+
do {
40+
try await inAppPurchasesForWPComPlansManager.purchaseProduct(with: product.id, for: siteID)
41+
} catch {
42+
purchaseError = PurchaseError(error: error)
43+
}
3444
await loadUserEntitlements()
3545
isPurchasing = false
3646
}
3747
}
48+
.alert(isPresented: $presentAlert, error: purchaseError, actions: {})
3849
}
3950
}
4051
}
@@ -102,6 +113,20 @@ struct InAppPurchasesDebugView: View {
102113
}
103114
}
104115

116+
/// Just a silly little wrapper because SwiftUI's `alert(isPresented:error:actions:)` wants a `LocalizedError`
117+
/// but we only have an `Error` coming from `purchaseProduct`.
118+
private struct PurchaseError: LocalizedError {
119+
let error: Error
120+
121+
var errorDescription: String? {
122+
if let error = error as? LocalizedError {
123+
return error.errorDescription
124+
} else {
125+
return error.localizedDescription
126+
}
127+
}
128+
}
129+
105130
struct InAppPurchasesDebugView_Previews: PreviewProvider {
106131
static var previews: some View {
107132
InAppPurchasesDebugView(siteID: 0)

Yosemite/Yosemite/Stores/InAppPurchaseStore.swift

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,23 @@ private extension InAppPurchaseStore {
9494

9595
logInfo("Purchasing product \(product.id) for site \(siteID) with options \(purchaseOptions)")
9696
let purchaseResult = try await product.purchase(options: purchaseOptions)
97-
if case .success(let result) = purchaseResult {
98-
logInfo("Purchased product \(product.id) for site \(siteID): \(result)")
99-
try await handleCompletedTransaction(result)
100-
} else {
101-
logError("Ignorning unsuccessful purchase: \(purchaseResult)")
97+
switch purchaseResult {
98+
case .success(let result):
99+
guard case .verified(let transaction) = result else {
100+
// Ignore unverified transactions.
101+
logError("Transaction unverified: \(result)")
102+
throw Errors.unverifiedTransaction
103+
}
104+
logInfo("Purchased product \(product.id) for site \(siteID): \(transaction)")
105+
106+
try await submitTransaction(transaction)
107+
await transaction.finish()
108+
case .userCancelled:
109+
logInfo("User cancelled the purchase flow")
110+
case .pending:
111+
logError("Purchase returned in a pending state, it might succeed in the future")
112+
@unknown default:
113+
logError("Unknown result for purchase: \(purchaseResult)")
102114
}
103115
completion(.success(purchaseResult))
104116
} catch {
@@ -265,13 +277,67 @@ private extension InAppPurchaseStore {
265277
}
266278

267279
public extension InAppPurchaseStore {
268-
enum Errors: Error {
280+
enum Errors: Error, LocalizedError {
281+
/// The purchase was successful but the transaction was unverified
282+
///
283+
case unverifiedTransaction
284+
285+
/// The purchase was successful but it's not associated to an account
286+
///
269287
case transactionMissingAppAccountToken
288+
289+
/// The transaction has an associated account but it can't be translated to a site
290+
///
270291
case appAccountTokenMissingSiteIdentifier
292+
293+
/// The transaction is associated with an unknown product
294+
///
271295
case transactionProductUnknown
296+
297+
/// The storefront for the user is unknown, and so we can't know their country code
298+
///
272299
case storefrontUnknown
300+
301+
/// App receipt was missing, even after a refresh
302+
///
273303
case missingAppReceipt
304+
305+
/// In-app purchases are not supported for this user
306+
///
274307
case inAppPurchasesNotSupported
308+
309+
public var errorDescription: String? {
310+
switch self {
311+
case .unverifiedTransaction:
312+
return NSLocalizedString(
313+
"The purchase transaction couldn't be verified",
314+
comment: "Error message used when a purchase was successful but its transaction was unverified")
315+
case .transactionMissingAppAccountToken:
316+
return NSLocalizedString(
317+
"Purchase transaction missing account information",
318+
comment: "Error message used when the purchase transaction doesn't have the right metadata to associate to a specific site")
319+
case .appAccountTokenMissingSiteIdentifier:
320+
return NSLocalizedString(
321+
"Purchase transaction can't be associated to a site",
322+
comment: "Error message used when the purchase transaction doesn't have the right metadata to associate to a specific site")
323+
case .transactionProductUnknown:
324+
return NSLocalizedString(
325+
"Purchase transaction received for an unknown product",
326+
comment: "Error message used when we received a transaction for an unknown product")
327+
case .storefrontUnknown:
328+
return NSLocalizedString(
329+
"Couldn't determine App Stoure country",
330+
comment: "Error message used when we can't determine the user's App Store country")
331+
case .missingAppReceipt:
332+
return NSLocalizedString(
333+
"Couldn't retrieve app receipt",
334+
comment: "Error message used when we can't read the app receipt")
335+
case .inAppPurchasesNotSupported:
336+
return NSLocalizedString(
337+
"In-app purchases are not supported for this user yet",
338+
comment: "Error message used when In-app purchases are not supported for this user/site")
339+
}
340+
}
275341
}
276342

277343
enum Constants {

0 commit comments

Comments
 (0)