superwall / Superwall-iOS

Remotely configure every aspect of your paywall and double your revenue.
https://superwall.com
MIT License
86 stars 22 forks source link

[BUG] - Seeing Many More Transaction Fails after Upgrading to SDK 3.0 #146

Closed michaeljajou closed 1 year ago

michaeljajou commented 1 year ago

General information

Describe the bug

I am seeing a lot more transaction fails after upgrading to SDK 3.0. I am not able to reproduce this myself, but I am able to see this in Mixpanel events from my users.

I am using the RevenueCat implementation - so the Transaction Fail is coming back with the error "Purchase Info Not Found"

    func purchase(product: SKProduct) async -> SuperwallKit.PurchaseResult {
        do {
            let storeProduct = RevenueCat.StoreProduct(sk1Product: product)
            let info = try await Purchases.shared.purchase(product: storeProduct)
            let isSubscribed = info.customerInfo.isProActive()
            UseCaseSetIsCurrentUserSubscribed.shared.execute(membership: isSubscribed ? .pro : .free)
            return isSubscribed ? .purchased : .failed(AppError.payment(type: .purchaseInfoNotFound))
        } catch {
            Log.error(error.localizedDescription)
            return .failed(error)
        }
    }
michaeljajou commented 1 year ago

Note: Oddly enough, I have not seen any Transaction Abandon evens coming through. I noticed that the example project checks for a PurchaseCancelled error - is it possible that these transaction fails are really transaction abandons? In SDK 2.0, transaction fails were logged automatically - but I guess it would make sense if I have to check for a cancelled transaction manually now

yusuftor commented 1 year ago

Hi @michaeljajou, your code needs to check for transaction abandons, as well as pending transactions, and tell Superwall. We report what you tell us. You're sending back a .failed error if the user didn't purchase or any kind of error is thrown. However, an abandoned transaction is being counted as a fail there. You should modify your code to be like this:

func purchase(product: SKProduct) async -> SuperwallKit.PurchaseResult {
    do {
      let storeProduct = RevenueCat.StoreProduct(sk1Product: product)
      let info = try await Purchases.shared.purchase(product: storeProduct)
      let isSubscribed = info.customerInfo.isProActive()
      UseCaseSetIsCurrentUserSubscribed.shared.execute(membership: isSubscribed ? .pro : .free)

      if info.userCancelled {
        return .cancelled
      } else {
        return .purchased
      }
    } catch let error as ErrorCode {
      if error == .paymentPendingError {
        return .pending
      } else {
        return .failed(error)
      }
    } catch {
      return .failed(error)
    }
  }

This is taken from our docs about using Superwall with RevenueCat.