Sandbox users always are owning application

Hi!

I'm trying to implement a two week free trial for my existing paid ipad app. Following the guidance from the wwdc2022/10007, I'm using AppTransaction.shared and checking the result. I'm getting a verified result, but the appTransaction.originalPurchaseDate is always the same date - 2013-08-01 07:00:00 +0000 / 397033200, even the particular sandbox account user never had a purchase.

This makes testing the logical branch of "has this user never purchased this app before" if the app store is always telling us that it's been purchased. (I've been using new sandbox account, so there should be no history)

Here's some code that includes hacking around always getting that original purchase date. We're in the final stretches, and wanting to test things that will be closer to actual store behavior (and I'm thinking that always returning a purchased date for an unpurchased app wouldn't be happening)

Am I just holding things wrong? Sandbox bug/limitatiin I just have to live with?

thanks! ++md

class MJAppStore: NSObject {
    @objc static let shared = MJAppStore()
    
    @objc func verifyAppStoreStatus(_ completion: @escaping (MJAppStoreStatus, Error?) -> Void) {
        Task {
            do {
                let status = try await doVerificationThing()
                completion(status, nil)
            } catch {
                completion(.error, error)
            }
        }
    }

    func doVerificationThing() async throws -> MJAppStoreStatus {
        do {
            let result = try await AppTransaction.shared
            print("TRIAL: survived AppTransaction.shared")
            
            switch result {
            case .unverified(_, _):
                print("TRIAL: app transaction UNVERIFIED")
                return .free
            case .verified(_):
                let appTransaction = try result.payloadValue

                // hack around the app store sandbox accounts saying we're purchased even though
                // we're not really. 2013-08-01 07:00:00 +0000
                print("TRIAL: app transaction VERIFIED \(appTransaction.originalPurchaseDate.timeIntervalSinceReferenceDate) -> \(appTransaction.originalPurchaseDate)")

                if appTransaction.originalPurchaseDate.timeIntervalSinceReferenceDate == 397033200 {
                    return .free
                } else {
                    return .purchased
                }
            }

        } catch {
            ...
Answered by App Store Commerce Engineer in 792476022

Hello! Use originalAppVersion instead, as mentioned in What's new with in-app purchase | WWDC22:

Customers that purchased my app should be granted the services they paid for. For this, I'll use the original app version property. This property lets me know the app version in which the customer had downloaded my app for the very first time.

Also see Supporting business model changes by using the app transaction:

In version 2, the developer wants to continue to provide the premium features to customers who purchased version 1. To do so, the app performs the following steps:

  1. The app’s code includes a constant that indicates the version the business model changed; that constant is "2" in this example.
  2. The app compares the originalAppVersion value with the constant. If the customer purchased the app before the business model changed, the app determines that they’re entitled to the premium features.
  3. The app also checks the currentEntitlements sequence and delivers any in-app purchases the customers may have made.
Accepted Answer

Hello! Use originalAppVersion instead, as mentioned in What's new with in-app purchase | WWDC22:

Customers that purchased my app should be granted the services they paid for. For this, I'll use the original app version property. This property lets me know the app version in which the customer had downloaded my app for the very first time.

Also see Supporting business model changes by using the app transaction:

In version 2, the developer wants to continue to provide the premium features to customers who purchased version 1. To do so, the app performs the following steps:

  1. The app’s code includes a constant that indicates the version the business model changed; that constant is "2" in this example.
  2. The app compares the originalAppVersion value with the constant. If the customer purchased the app before the business model changed, the app determines that they’re entitled to the premium features.
  3. The app also checks the currentEntitlements sequence and delivers any in-app purchases the customers may have made.

And to follow up. With a sandbox account in the simulator.

  • I'm on (e.g.) version 65
  • I purchase the app. Then re-run
  • get originalAppVersion of 65
  • I bump my app version to 66 and re-run
  • originalAppVersion now returns 66. So I'm unable to tell that I've actually purchased.

Do I have to run this on a device and/or off of TestFlight to get it use the version when I do a fake purchase?

thanks!

PEBCAK - need to upgrade both the version numbers for it to stick.

Getting these values when running on the device (testflight not involved):

  • version 2.8.4 / 72 - "bought"
  • version 2.8.5 / 73 - returned 72 (so interpret as purchased)
  • version 2.8.6 / 74 - returned 74 (so interpret as free version)
  • version 2.8.7 / 75 - returned 75 (so interpret as free version)

The app compares the originalAppVersion value with the constant.

But, as I have discovered, in sandbox situations, the originalAppVersion always returns 1.0. Is it possible to test this stuff before releasing it?

Sandbox users always are owning application
 
 
Q