Swift:内购消耗品只能购买一次

Swift: In-App Purchase consumable can be purchased just once

我正在使用应用内购买在 SwiftUI 中制作应用。在这个应用程序中,用户应该可以多次购买积分,所以我使用了消耗品。但是当我再次尝试购买它们时,我得到的信息是“此应用程序内购买已经购买。它将免费恢复”。我已经在寻找方法,但 none 的想法对我有用。

这是我的 StoreManager class:

import Foundation
import StoreKit
import SwiftUI

class StoreManager : NSObject, ObservableObject, SKProductsRequestDelegate {
    
    @EnvironmentObject var authViewModel: AuthViewModel
    
    @Published var transactionState: SKPaymentTransactionState?
    @Published var myProducts = [SKProduct]()
    var request: SKProductsRequest!
    
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        print("Did receive response")
        
        if !response.products.isEmpty {
            for fetchedProduct in response.products {
                    DispatchQueue.main.async {
                        self.myProducts.append(fetchedProduct)
                }
            }
            for invalidIdentifier in response.invalidProductIdentifiers {
                print("Invalid identifiers found: \(invalidIdentifier)")
            }
        }else{
            print("it's empty")
        }
    }
    
    func getProducts(productIDs: [String]) {
        let request = SKProductsRequest(productIdentifiers: Set(productIDs))
        request.delegate = self
        request.start()
    }
    
    func request(_ request: SKRequest, didFailWithError error: Error) {
        print("Request did fail: \(error)")
    }
    
    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        for transaction in transactions {
            switch transaction.transactionState {
            case .purchasing:
                transactionState = .purchasing
                break
            case .purchased:
                print("purchased")
                queue.finishTransaction(transaction)
                transactionState = .purchased
                break
            case .restored:
                print("restored")
                transactionState = .restored
                queue.finishTransaction(transaction)
                break
            case .failed, .deferred:
                    queue.finishTransaction(transaction)
                    transactionState = .failed
                break
                    default:
                    queue.finishTransaction(transaction)
                break
            }
        }
    }
    
    func purchaseProduct(product: SKProduct) {
        
        if SKPaymentQueue.canMakePayments() {
            let payment = SKPayment(product: product)
            SKPaymentQueue.default().add(payment)

        } else {
            print("User can't make payment.")
        }
    }
    
    func restoreProducts() {
        SKPaymentQueue.default().restoreCompletedTransactions()
    }
}

我只是将 getProducts 与 onAppear 一起使用,并根据按钮的操作购买产品。

请帮助我,或者如果类似问题的答案已经存在,请给我发一个 link 到那个线程。

这是因为有两种类型的应用内购买。消耗品和 非消耗品。消费类应用内购买可以多次进行,非消费类应用内购买只能进行一次。

https://developer.apple.com/in-app-purchase/

解决方案

在 App Store Connect 应用内购买部分查看您创建的应用内购买类型。如果它是非消耗品,则删除现有的应用内购买并创建一个新的消耗品。

资源

Implement In App Purchase (IAP) in iOS applications

Adding In-App Purchases to a SwiftUI App

你的 StoreManager class 需要符合 SKPaymentTransactionObserver - 你已经从这个协议中实现了相关的委托方法,但是你没有声明一致性,或者最重要的是,添加您的 StoreManager 实例作为事务队列观察者。

由于您没有观察交易,因此您永远不会调用 finishTransaction - 当您第二次尝试购买消耗品时,Store Kit 会发现该物品的购买不完整,因此您收到您已购买的消息。

除了实际注册为事务队列观察器之外,重要的是您的应用程序在启动后立即创建 StoreManager 的实例 - 在 didFinishLaunching 或等效位置。

这样一来,之前 运行 的任何未完成购买都可以呈现给您的交易队列观察员。

你应该只有一个 StoreManager 的实例,它的生命周期应该是你的应用程序的生命周期。

你需要这样的东西:

class StoreManager : NSObject, ObservableObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
    init() {
         SKPaymentQueue.default().add(self)
    }

此外,看到 @EnvironmentObject var authViewModel: AuthViewModel 让我认为您的设计中可能存在关注点分离问题。