How to make a purchase in visionOS?'purchase(options:)' is unavailable in visionOS

229 views Asked by At

the code I had fully functional in production is not working for the visionOS, what the heck? I get this error

'purchase(options:)' is unavailable in visionOS: Use @Environment(.purchase) to get a PurchaseAction value to call. If your app uses UIKit, use purchase(confirmIn:options:).

how can I change my code to please visionos demands?

    func purchase(_ product: Product) async throws -> Transaction? {
        
        let result = try await product.purchase() //TEMPORARY JAN-23
        
        switch result {
        case .success(let verification):
            // Successful purchase

    
                //Check whether the transaction is verified. If it isn't,
                //this function rethrows the verification error.
                let transaction = try checkVerified(verification)

                //The transaction is verified. Deliver content to the user.
                await updateCustomerProductStatus()

UPDATE: I REALIZED i need to do purchase the ios17 way, but they ios16 purchase style cannot coexist with ios17 style!! wth!!

I cannot do this

struct PaymentViewVoice: View {
    @Environment(\.presentationMode) var presentationMode
    @EnvironmentObject private var store: Store
    @Environment(\.purchase) var purchase // For iOS 17 payments

error: 'purchase' is only available in iOS 17.0 or newer

and I cannot do this

struct PaymentViewVoice: View {
    @Environment(\.presentationMode) var presentationMode
    @EnvironmentObject private var store: Store //for ios6 payments
    @available(iOS 17.0, *)
    @Environment(\.purchase) var purchase // For iOS 17 payments

error: Stored properties cannot be marked potentially unavailable with '@available'

1

There are 1 answers

6
HangarRash On BEST ANSWER

visionOS requires SwiftUI code that is only available with iOS 17.0+. Your iOS app supports iOS 16.0+. One solution is to use compiler directives so that the SwiftUI/iOS 17+ code is only built for the visionOS version of the app and the "older", non-SwiftUI, StoreKit APIs are used for the iOS version of the app.

Something like the following:

struct PaymentViewVoice: View {
    @Environment(\.presentationMode) var presentationMode
    @EnvironmentObject private var store: Store
#if os(visionOS)
    @Environment(\.purchase) var purchase // For iOS 17 payments
#endif

If you have any code that is only for the SwiftUI/iOS 17+/visionOS version, wrap that code in:

#if os(visionOS)
#endif

If you have any code that is only for the iOS version (both iOS 16 or iOS 17), wrap that code in:

#if os(iOS)
#endif

If you have a section where there is code for both, wrap the code in:

#if os(visionOS)
    // visionOS specific code
#else
    // iOS specific code
#endif

One simplified example might be in a button handler:

Button {
    Task {
        let purchaseResult: Product.PurchaseResult
#if os(visionOS)
        // visionOS specific code
        purchaseResult = try await purchase(product)
#else
        // iOS specific code
        purchaseResult = try await product.purchase() 
#endif
        // Process the purchase result.
        switch purchaseResult {
        }
    } 
} label: {
    Text("Purchase")
}