Skip to main content
Question

Independent watchOS app, subscription purchase fails on device (Xcode and TestFlight)

  • 4 January 2022
  • 2 replies
  • 757 views

Context:

  • New, 1.0 release of an app
  • Independent watchOS app, e.g. no iOS app
  • Purchases work in sandbox/simulator and see them show up on the RevenueCat dashboard when viewing sandbox data
  • I’m using the Purchases framework version 3.13.1 with SPM

When I build and run on my physical Apple Watch and attempt to purchase, I get this failure message:

Unable to Purchase App

Sign in with your Apple ID from the Apple Watch app on your iPhone

p OK ]

But I am already signed in with my personal Apple ID account AND have my Sandbox Account configured on my iPhone.

My logs look like with a fresh install/build from Xcode:

2022-01-04 12:46:15.726123-0700 Next WatchKit Extensiono370:89772] ]Purchases] - DEBUG: ℹ️ Debug logging enabled

2022-01-04 12:46:15.727275-0700 Next WatchKit Extensione370:89772] 9Purchases] - DEBUG: ℹ️ SDK Version - 3.13.1

2022-01-04 12:46:15.727348-0700 Next WatchKit Extension 370:89772] 7Purchases] - DEBUG: 👤 Initial App User ID - (null)

2022-01-04 12:46:16.034222-0700 Next WatchKit ExtensionK370:89772] nPurchases] - DEBUG: ℹ️ No cached Offerings, fetching from network

2022-01-04 12:46:16.095313-0700 Next WatchKit Extensiona370:89772] nPurchases] - DEBUG: ℹ️ PurchaserInfo cache is stale, updating from network in foreground.

2022-01-04 12:46:16.096663-0700 Next WatchKit Extensionx370:89772] EPurchases] - DEBUG: 😻 PurchaserInfo updated from network.

2022-01-04 12:46:16.105116-0700 Next WatchKit Extension 370:90003] iPurchases] - DEBUG: ℹ️ There are no requests currently running, starting request GET /subscribers/$RCAnonymousID0X0P+050359f9165194c4bbf1fbcbc5462399b

2022-01-04 12:46:16.105217-0700 Next WatchKit Extension0370:90003] tPurchases] - DEBUG: ℹ️ API request started: GET /v1/subscribers/$RCAnonymousID:50359f9165194c4bbf1fbcbc5462399b

2022-01-04 12:46:16.111246-0700 Next WatchKit Extension2370:89772] tscenes] unable to send specifiers:<__NSArrayM: 0x155652c0; count: 1> {

    <BLSAlwaysOnDateSpecifier: 0x155f8e30; date: 12:46:05.572; fidelity: Never>;

} response to frameSpecifiersAction:<BLSFrameSpecifiersRequestAction: 0x15679e10; info: <BSSettings: 0x15679e30> {

    (1) = <_NSConcreteDateInterval: 0x1567ac20> (Start Date) 2022-01-04 19:46:05 +0000 + (Duration) 840.000000 seconds = (End Date) 2022-01-04 20:00:05 +0000;

    (3) = BSSettingFlagYes;

}; responder: <_BSActionResponder: 0x15679520; active: YES; waiting: NO> clientInvalidated = NO;

clientEncoded = NO;

clientResponded = NO;

reply = <BSMachPortSendOnceRight: 0x1567ac30; usable: NO; (370:0:send-once xpcCode) from (45:0:send-once take)>;

annulled = YES;>

2022-01-04 12:46:16.112486-0700 Next WatchKit Extension1370:90003] 0Purchases] - DEBUG: ℹ️ There's a request currently running and 0 requests left in the queue, queueing GET /subscribers/$RCAnonymousID0X0P+050359f9165194c4bbf1fbcbc5462399b/offerings

2022-01-04 12:46:17.568690-0700 Next WatchKit Extension:370:89995] 0Purchases] - DEBUG: ℹ️ API request completed with status: GET /v1/subscribers/$RCAnonymousID:50359f9165194c4bbf1fbcbc5462399b 200

2022-01-04 12:46:17.584104-0700 Next WatchKit Extension4370:89772] 8scenes] unable to send desiredFidelity:Never response to desiredFidelityAction:<BLSDesiredFidelityAction: 0x1567f4f0; info: 0x0; responder: <_BSActionResponder: 0x1567b5a0; active: YES; waiting: NO> clientInvalidated = NO;

clientEncoded = NO;

clientResponded = NO;

reply = <BSMachPortSendOnceRight: 0x156fa210; usable: NO; (370:0:send-once xpcCode) from (45:0:send-once take)>;

annulled = YES;>

2022-01-04 12:46:17.592104-0700 Next WatchKit Extension4370:89995] 9Purchases] - DEBUG: ℹ️ Serial request done: GET /subscribers/$RCAnonymousID0X0P+050359f9165194c4bbf1fbcbc5462399b, 1 requests left in the queue

2022-01-04 12:46:17.592338-0700 Next WatchKit Extension0370:89995] 1Purchases] - DEBUG: ℹ️ Starting the next request in the queue, <RCHTTPRequest: httpMethod=GET

path=/subscribers/$RCAnonymousID0X0P+050359f9165194c4bbf1fbcbc5462399b/offerings

requestBody=(null)

headers={

    Authorization = "Bearer appl_tvUrSwzGWpZrCaOvFTTuMbCmfdR";

}

retried=0

>

2022-01-04 12:46:17.594933-0700 Next WatchKit Extension>370:89995] 1Purchases] - DEBUG: ℹ️ There are no requests currently running, starting request GET /subscribers/$RCAnonymousID0X0P+050359f9165194c4bbf1fbcbc5462399b/offerings

2022-01-04 12:46:17.595002-0700 Next WatchKit Extensionb370:89995] -Purchases] - DEBUG: ℹ️ API request started: GET /v1/subscribers/$RCAnonymousID:50359f9165194c4bbf1fbcbc5462399b/offerings

2022-01-04 12:46:18.147652-0700 Next WatchKit Extension 370:90002] 2Purchases] - DEBUG: ℹ️ API request completed with status: GET /v1/subscribers/$RCAnonymousID:50359f9165194c4bbf1fbcbc5462399b/offerings 200

2022-01-04 12:46:18.153605-0700 Next WatchKit Extension0370:90002] >Purchases] - DEBUG: ℹ️ Requesting products from the store with identifiers: {(

    "next_watchos_59.99_annually_1_month_free"

)}

2022-01-04 12:46:18.154358-0700 Next WatchKit Extensionb370:90002] >Purchases] - DEBUG: ℹ️ Serial request done: GET /subscribers/$RCAnonymousID0X0P+050359f9165194c4bbf1fbcbc5462399b/offerings, 0 requests left in the queue

2022-01-04 12:46:19.284917-0700 Next WatchKit Extensionn370:90002] bPurchases] - DEBUG: ℹ️ Products request finished.

2022-01-04 12:46:19.285092-0700 Next WatchKit Extensionq370:90002] ePurchases] - DEBUG: 💰 Retrieved SKProducts:

2022-01-04 12:46:19.285612-0700 Next WatchKit Extensionr370:90002] dPurchases] - DEBUG: 💰 next_watchos_59.99_annually_1_month_free - <SKProduct: 0x15647a10>

2022-01-04 12:46:19.285824-0700 Next WatchKit Extensiono370:90002] 4Purchases] - DEBUG: ℹ️ 2 completion handlers waiting on products

2022-01-04 12:47:12.165478-0700 Next WatchKit Extensiond370:89772] gPurchases] - DEBUG: ℹ️ makePurchase

2022-01-04 12:47:12.169755-0700 Next WatchKit Extension 370:89772] Purchases] - DEBUG: 💰 Purchasing product from package  - next_watchos_59.99_annually_1_month_free in Offering default

2022-01-04 12:47:12.170124-0700 Next WatchKit Extension_370:89999] ePurchases] - DEBUG: ℹ️ PaymentQueue updatedTransaction: next_watchos_59.99_annually_1_month_free (null) ((null)) (null) - 0

2022-01-04 12:47:43.176784-0700 Next WatchKit Extensionm370:91940] <SKPaymentQueue: 0x155e0210>: Payment completed with error: Error Domain=ASDErrorDomain Code=530 "The operation couldn’t be completed. (ASDErrorDomain error 530.)" UserInfo={NSLocalizedDescription=The operation couldn’t be completed. (ASDErrorDomain error 530.)}

2022-01-04 12:47:43.186559-0700 Next WatchKit Extensione370:91940] Purchases] - DEBUG: ℹ️ PaymentQueue updatedTransaction: next_watchos_59.99_annually_1_month_free (null) (Error Domain=SKErrorDomain Code=0 "UNKNOWN_ERROR" UserInfo={NSUnderlyingError=0x15615a00 {Error Domain=ASDErrorDomain Code=530 "The operation couldn’t be completed. (ASDErrorDomain error 530.)" UserInfo={NSLocalizedDescription=The operation couldn’t be completed. (ASDErrorDomain error 530.)}}, NSLocalizedDescription=UNKNOWN_ERROR}) (null) - 2

2022-01-04 12:47:43.186925-0700 Next WatchKit ExtensionN370:89772] ePurchases] - ERROR: 🍎‼️ There was a problem with the App Store.

2022-01-04 12:47:43.187083-0700 Next WatchKit ExtensionR370:91940] Purchases] - DEBUG: 💰 Finishing transaction next_watchos_59.99_annually_1_month_free (null) ((null))

2022-01-04 12:47:43.188266-0700 Next WatchKit Extensiono370:91940] hPurchases] - DEBUG: ℹ️ PaymentQueue removedTransaction: next_watchos_59.99_annually_1_month_free (null) ((null) Error Domain=SKErrorDomain Code=0 "UNKNOWN_ERROR" UserInfo={NSUnderlyingError=0x15615a00 {Error Domain=ASDErrorDomain Code=530 "The operation couldn’t be completed. (ASDErrorDomain error 530.)" UserInfo={NSLocalizedDescription=The operation couldn’t be completed. (ASDErrorDomain error 530.)}}, NSLocalizedDescription=UNKNOWN_ERROR}) {

    NSLocalizedDescription = "UNKNOWN_ERROR";

    NSUnderlyingError = "Error Domain=ASDErrorDomain Code=530 \"The operation couldn\U2019t be completed. (ASDErrorDomain error 530.)\" UserInfo={NSLocalizedDescription=The operation couldn\U2019t be completed. (ASDErrorDomain error 530.)}";

} - 2

When I submit this app for App Store review it is rejected with this message:

We discovered one or more bugs in your app. Specifically, the subscription button was unresponsive. Please review the details below and complete the next steps.

Review device details:

- Device type: Watch

- OS version: watchOS 8.3

My subscription code feels very basic/simple to me, but including incase I’m missing something very obvious:

class SubscriptionManager: ObservableObject {

    let entitlementIdentifier = "unlimited"

    

    @Published private(set) var isSubscribed: Bool = false

    

    var currentOffering: Purchases.Offering? = nil

    

    func verifySubscriptionStatus() {

        Purchases.shared.purchaserInfo { (purchaserInfo, error) in

            if purchaserInfo?.entitlements.allyself.entitlementIdentifier]?.isActive == true {

                self.isSubscribed = true

            }

        }

    }

    

    func purchaseSubscription() {

        if let package = currentOffering?.availablePackages.first {

            Purchases.shared.purchasePackage(package) { (transaction, purchaserInfo, error, userCancelled) in

                if purchaserInfo?.entitlements.allaself.entitlementIdentifier]?.isActive == true {

                    self.isSubscribed = true

                }

            }

        }

    }

    

    func restorePurchases() {

        Purchases.shared.restoreTransactions { (purchaserInfo, error) in

            if error != nil {

                // do something with the error at some point...

            } else {

                self.isSubscribed = true

            }

        }

    }

    

    func fetchOfferings() {

        Purchases.shared.offerings { (offerings, error) in

            if let error = error {

                print(error.localizedDescription)

            }

            self.currentOffering = offerings?.current

        }

    }

    

    init() {

        verifySubscriptionStatus()

        fetchOfferings()

    }

}

Any ideas what might be causing Purchases to fail on my Apple Watch when running from Xcode or TestFlight?

Your code looks fine, the dreaded UNKNOWN_ERROR from Apple is always a tricky one to troubleshoot, but I bet it’s related to that first screenshot of not being able to sign in.

From the logs the products are able to fetch fine, so there is some connection to StoreKit happening there…

Sometimes searching for the ASDError will pop up some helpful results. Unfortunately Apple has 0 documentation on the ASDErrorDomain namespace or how to handle it so there’s no “official” way to resolve the error other than the Unknown Error Docs.

When this error occurs during testing, it can often be resolved by logging out of iTunes and/or the App Store and creating a new test user account in App Store Connect. This approach only works when running the app on a device, not the simulator.

When this error occurs in production, it may indicate a problem with the user’s iTunes account.

 

A little strange I only see 1 other post on the internet with the specific ASDErrorDomain Code=530https://stackoverflow.com/questions/66560647/skreceiptrefreshrequest-failed-with-asderrordomain-code-530. The one answer there feels a little voodoo to me, but does point back to some issue with the sandbox/testflight account. 

I would try creating a new sandbox account and signing in with that. For some folks it looks like some apps being updated in the background were causing a similar issue: https://discussions.apple.com/thread/250668295

 


I have the same very problem (has to sign in with your appleID) and my app is also stuck in review with the same very rejection reason.

It seems to me that something has changed (is broken) on the Apple side, since I already have an Apple Watch only app in store and purchases in sandbox environment via RevenueCat also stopped working for it (although everything still works fine in production). And purchases did work before.

What I’ve done:

  1. Created a video of purchases working in Xcode using local storeKit file
  2. Made some errors handling and display

Will try to submit all that including link to this thread and let’s hope it will work out.

If not, I’ll file a bug.


Reply