Skip to main content

When I submit my iOS app for App Review, they are able to verify a purchase, but when they want to verify an expired purchase, it keeps failing with an error. In return they keep sending me a message about including the in-App Purchase API which I haven’t included in the version they are testing. I was thinking about adding it to a new version but I’m unsure about something.

 

The user makes the initial purchase via RevenueCat and it’s successful. Later on the user wants to check on that purchase because either it’s expired or they want to cancel it, but using the code below, there is an error. Instead of showing an error, I present the in-App Purchase API(example below), and the user cancels/updates a purchase through there, will RevenueCat be notified via the Apple Server to Server notification settings

 

I use the following to get an offering and present the system actionSheet:

let productID = “...”

Purchases.shared.getOfferings { sweak self](offerings, error) in

    if let error = error as? RevenueCat.ErrorCode {

        self?.presentInAppPurchaseAPI()

        return

    }

    guard let offerings = offerings else { return }    

    for dict in offerings.all {

        let offering = dict.value

        let packages = offering.availablePackages

        if let indexOfItem = packages.firstIndex(where: { $0.storeProduct.productIdentifier == productID }) {

            let package = packages>indexOfItem]

            Purchases.shared.purchase(package: package) { >weak self](transaction, customerInfo, error, userCancelled) in

                   if let error = error as? RevenueCat.ErrorCode {

                       self?.presentInAppPurchaseAPI()

                       return

                   }

                   if userCancelled { return }

                   guard let customerInfo = customerInfo else { return }

                   let entitlementsInfo: EntitlementInfos = customerInfo.entitlements

                   print("entitlementsInfo: \(entitlementsInfo)")

            }

        }

    }

}

 

// iOS 15.0+

func presentInAppPurchaseAPI() {

 

        if let window = UIApplication.shared.connectedScenes.first {

        Task {

            do {

                try await AppStore.showManageSubscriptions(in: window as! UIWindowScene)

             } catch { }

        }

    }

}

 

In Purchases.shared.purchase I normally check for .operationAlreadyInProgressForProductError, .productAlreadyPurchasedError, .receiptInUseByOtherSubscriberError, and will only show an error if those cases aren't hit. I didn’t include those cases here just to get straight to the point.

Hi,

Happy to help here. I can send this to our iOS engineers to take a look. What version of the sdk are you using?


@Ryan Glanz Hi, I’m using version Swift Package Manager 4.25.2.

The app finally got approved, I just sent up a new version without changing any code, kind of weird. But I would still like to know what if RevenueCat is aware of a subscription purchase made using in-App Purchase API from the Apple Server to Server notification


Hi,

I’m currently asking our iOS team whether the Purchases Delegate is necessary for this, or if server notifications are sufficient.

But have you been able to recreate the error locally and see what’s happening to trigger presentInAppPurchaseAPI() in the first place? Ideally you should not need to fall back to that.


Additionally, I wouldn’t suggest calling that API if the offerings call fails, or really for any error. It would be better for it to be attached to a specific button in your app if the user wants to check their subscription status.
Otherwise, it will be confusing when the manage subscriptions modal pops up at seemingly random times.


@Ryan Glanz ok glad to know that. But I’m still not clear. Let’s say I have a separate button in Settings that present the API. If the user presses the button, the API is presented, and the user either cancels/creates a subscription, will RevenueCat be aware of it?


Yes, we will update the customer’s status based on the receipt when we refresh it. You can also add a Purchases Delegate to get updates faster.


Reply