Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 应用内购买:购买后给用户购买的物品_Ios_Swift_In App Purchase_Nsuserdefaults - Fatal编程技术网

Ios 应用内购买:购买后给用户购买的物品

Ios 应用内购买:购买后给用户购买的物品,ios,swift,in-app-purchase,nsuserdefaults,Ios,Swift,In App Purchase,Nsuserdefaults,这是一个由两部分组成的问题,相互关联,不值得单独问 第一个问题 所以我刚刚在youtube上完成了一个关于应用程序内购买的指南教程,他主要介绍了购买物品的实际付款和恢复等 但有一件事他没有提到,我实际上需要的是一种方式,实际上是给买家(在我的例子中是游戏中的硬币)购买的物品 这是包含所有购买功能和其他内容的文件 import Foundation import StoreKit class IAPService: NSObject { private override init()

这是一个由两部分组成的问题,相互关联,不值得单独问

第一个问题

所以我刚刚在youtube上完成了一个关于应用程序内购买的指南教程,他主要介绍了购买物品的实际付款和恢复等

但有一件事他没有提到,我实际上需要的是一种方式,实际上是给买家(在我的例子中是游戏中的硬币)购买的物品

这是包含所有购买功能和其他内容的文件

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更安全

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
    }
}

关于硬币存储,您可以将其同步到文件、存储在钥匙链中或使用服务器端存储,这可能是最好的选择。

谢谢,我会尝试这一点。是否没有其他方法可以让黑客无法访问某个值,而是将其存储在代码中?绝对没有办法让您的值不受黑客攻击,一切都是易碎的。但你可以让他们的生活更艰难,好吧,新问题,你的开关正在工作,我写了一个函数,返回一个整数,然后将它保存到用户默认值。现在,我该如何使它的值根据用户单击的单元格进行更改呢?非常感谢你的帮助,我现在已经完成了我的应用程序,也可以在明天启动我是否使整数值根据购买的产品而变化