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 应用内购买部分查看您创建的应用内购买类型。如果它是非消耗品,则删除现有的应用内购买并创建一个新的消耗品。
资源
你的 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
让我认为您的设计中可能存在关注点分离问题。
我正在使用应用内购买在 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 应用内购买部分查看您创建的应用内购买类型。如果它是非消耗品,则删除现有的应用内购买并创建一个新的消耗品。
资源
你的 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
让我认为您的设计中可能存在关注点分离问题。