这是一个两部分问题,相互联系,不值得分开问题
第一个问题
所以我刚刚在youtube here上完成了关于应用内购买的指南教程,他主要介绍了购买商品的实际付款和恢复等。
但是他没有说明我实际需要的一件事是实际上给买方(在我的情况下是游戏中的硬币)购买物品的方式
这是包含所有购买功能和其他内容的文件
import Foundation
import StoreKit
class IAPService: NSObject {
private override init() {}
static let shared = IAPService()
var products = [SKProduct]()
var paymentQueue = SKPaymentQueue.default()
func getProducts() {
let products: Set = [IAPProduct.StackOfCoins.rawValue,
IAPProduct.PileOfCoins.rawValue,
IAPProduct.BoxOfCoins.rawValue,
IAPProduct.MountainOfCoins.rawValue,
IAPProduct.ContainerOfCoins.rawValue]
let request = SKProductsRequest(productIdentifiers: products)
request.delegate = self
request.start()
paymentQueue.add(self)
}
func purchase(product: IAPProduct) {
guard let productToPurchase = products.filter({ $0.productIdentifier == product.rawValue }).first else { return }
let payment = SKPayment(product: productToPurchase)
paymentQueue.add(payment)
}
}
extension IAPService: SKProductsRequestDelegate {
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
self.products = response.products
print(response.products)
for product in response.products {
print(product.localizedDescription)
}
}
}
extension IAPService: SKPaymentTransactionObserver {
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
print(transaction.transactionState.status(), transaction.payment.productIdentifier)
switch transaction.transactionState {
case .purchasing: break
default: queue.finishTransaction(transaction)
}
}
}
}
extension SKPaymentTransactionState {
func status() -> String {
switch self {
case .deferred: return "deferred"
case .failed: return "failed"
case .purchased: return "purchased"
case .purchasing: return "purchasing"
case .restored: return "restored"
}
}
}
这是存储我的产品ID的第二个文件
import Foundation
//crappy duck is the name of my game i am developing and these here represent increasing values of coins the user can buy
enum IAPProduct: String {
case StackOfCoins = "com.HucksCorp.Crappy-duck.StackOfCoins"
case PileOfCoins = "com.HucksCorp.Crappy-duck.PileOfCoins"
case BoxOfCoins = "com.HucksCorp.Crappy-duck.BoxOfCoins"
case MountainOfCoins = "com.HucksCorp.Crappy-duck.MountainOfCoins"
case ContainerOfCoins = "com.HucksCorp.Crappy-duck.ContainerOfCoins"
}
它工作正常我可以连接和访问我的产品出售(游戏中的硬币)和所有这些,但我无法弄清楚如何更改它,以便它给用户基于项目的游戏币正在购买
这是我用来让用户真正购买东西的东西
这是一个集合视图
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
if indexPath.item == 0 {
IAPService.shared.pruchase(product: .StackOfCoins)
}
if indexPath.item == 1 {
IAPService.shared.purchase(product: .PileOfCoins)
}
if indexPath.item == 2 {
IAPService.shared.purchase(product: .BoxOfCoins)
}
if indexPath.item == 3 {
IAPService.shared.purchase(product: .MountainOfCoins)
}
if indexPath.item == 4 {
IAPService.shared.purchase(product: .ContainerOfCoins)
}
}
第二个问题
我将值硬币存储在UserDefaults中,而我之前的一个问题中的其他人警告我,将可购买产品存储在UserDefaults中是个坏主意
UserDefaults的第二个选项是什么,我可以通过应用内购买和游戏内可购买产品访问,添加和减少
摘要
如果我的问题不清楚(如果他们不让我知道,我可以编辑它们)我的第一个问题是如何在用户购买产品后向用户提供
我的第二个问题是 userDefaults值硬币的另一个选项,它比UserDefaults
更安全答案 0 :(得分:2)
在updatedTransactions
:
switch transaction.transactionState {
case .purchased:
let coinsValue = generateValue(transaction.payment.productIdentifier)
//add a call to your function here
break;
case .purchasing: break
default: queue.finishTransaction(transaction)
}
在这种情况下,根据购买的产品,调用添加硬币的方法。
这是从标识符获取int的方法:
private func generateValue(_ identifier: String) -> Int
{
switch identifier {
case "com.HucksCorp.Crappy-duck.StackOfCoins":
return 1
case "com.HucksCorp.Crappy-duck.PileOfCoins":
return 2
/// etc..
default:
return 0
}
}
关于硬币存储,您可以将它们同步到文件,存储在钥匙串中或使用服务器端存储,这可能是最佳选择。