swiftvisionosvisionos-simulator

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


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'


Solution

  • 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")
    }