gpt4 book ai didi

ios - 将IAP存储在UserDefaults中,这样用户无需每次按“可购买”按钮即可恢复购买

转载 作者:行者123 更新时间:2023-12-01 18:34:44 26 4
gpt4 key购买 nike

背景:我的应用程序从一组数组中提供了许多提示。 “包装”确定可以打开哪些提示。您从默认包装开始,然后可以为非消耗性IAP购买另外三个包装(packA,packB和packC)。

我的目标是让用户付款一次,然后可以在他/她喜欢的时候使用这些包装。但是,一旦沙盒用户创建了IAP,就会弹出一个窗口,说“您已经购买了它。是否要免费获得它?”。我显然不希望每次用户选择包装时都弹出此对话框。无论如何,是否可以使购买永久使用,而无需经常恢复购买?

下面是我当前的代码(匿名化并简化为基本组成部分):

import UIKit
import QuartzCore
import StoreKit

class ViewController: UIViewController, SKPaymentTransactionObserver {


//MAIN SETUP SECTION XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

let productID = "com.domain.appName.additionalPackages"
let defaults = UserDefaults.standard

//I'm just putting "Various" here as a placeholder for my multiple buttons
@IBOutlet weak var (Various): UIButton!

override func viewDidLoad() {
super.viewDidLoad()


SKPaymentQueue.default().add(self)

//I don’t know if this actually does anything
func cleanUp() {
for transaction in SKPaymentQueue.default().transactions {
SKPaymentQueue.default().finishTransaction(transaction)
}
}

}




//PACK SELECTION SECTION XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

var packA = 2
var packB = 2
var packC = 2
var packsUnlocked = false

@IBAction func selectPackA(_ sender: UIButton) {
if packsUnlocked == false {
print("It's locked, ‘Pack A’ not enabled")
} else if packCounterA % 2 == 0 {
if SKPaymentQueue.canMakePayments() { // In App Purchase
let paymentRequest = SKMutablePayment()
paymentRequest.productIdentifier = productID
SKPaymentQueue.default().add(paymentRequest)
print("Initiating Transaction")
} else {
print("No Purchased")
}
promptProvider.includeA.toggle()
packCounterA += 1
} else {
promptProvider.includeA.toggle()
packCounterA += 1
}
}

@IBAction func selectPackB(_ sender: UIButton) {
if packsUnlocked == false {
print("It's locked, ‘Pack B’ not enabled")
} else if packCounterB % 2 == 0 {
if SKPaymentQueue.canMakePayments() { // In App Purchase
let paymentRequest = SKMutablePayment()
paymentRequest.productIdentifier = productID
SKPaymentQueue.default().add(paymentRequest)
print("Initiating Transaction")
} else {
print("No Purchased")
}
promptProvider.includeB.toggle()
packCounterB += 1
} else {
promptProvider.includeB.toggle()
packCounterB += 1
}
}

@IBAction func selectPackC(_ sender: UIButton) {
if packsUnlocked == false {
print("It's locked, ‘Pack C' not enabled")
} else if packCounterC % 2 == 0 {
if SKPaymentQueue.canMakePayments() { // In App Purchase
let paymentRequest = SKMutablePayment()
paymentRequest.productIdentifier = productID
SKPaymentQueue.default().add(paymentRequest)
print("Initiating Transaction")
} else {
print("No Purchased")
}
promptProvider.includeC.toggle()
packCounterC += 1
} else {
promptProvider.includeC.toggle()
packCounterC += 1
}
}




//TRANSACTION FINALIZATION SECTION XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
guard
transaction.transactionState != .purchasing,
transaction.transactionState != .deferred
else {
//Optionally provide user feedback for pending or processing transactions
continue
}

if transaction.transactionState == .purchased || transaction.transactionState == .restored {
print("Transaction Successful")
packsUnlocked = true
//new
defaults.set(true, forKey: "Purchase Pack")
UserDefaults.standard.synchronize()
} else if transaction.transactionState == .failed {
print("Transaction Failed with error")
}

//Transaction can now be safely finished
queue.finishTransaction(transaction)
}
}



}

这是我的第一个应用程序,但我认为问题在于将购买保存到 UserDefaults。我对此很陌生,因此非常感谢您的帮助。

谢谢

最佳答案

基本

购买完成后,您可以通过Bundle.main.appStoreReceiptURL访问收据。您可以使用该收据并在App Store上进行验证,以防止他人使用伪造的收据。

验证回复将告诉您收据合法,尚未退款。它还告诉您订阅仍处于 Activity 状态以及何时到期。

您可以在客户端上执行所有这些操作,但是最好的做法是将收据存储在服务器上,以便您可以在末端进行验证,而不是将其交给客户端进行潜在的操作。

不要从以下位置 call App Store服务器verifyReceipt端点
您的应用。您无法在用户设备之间建立受信任的连接
和App Store,因为您无法控制
这种联系,使它容易受到中间人的影响
攻击。

您可以在docs中找到更多信息,包括代码示例。此外,您可以设置hooks,以便在订阅状态更改时主动通知您的服务器。

PoC

如果您不关心上述安全隐患,而只想进行概念验证,则可以在应用程序中执行此操作,并检查用户是否已经购买了商品:

  • Bundle.main.appStoreReceiptURL?.path接收收据
  • 按照here所述在App Store服务器上验证收据;请注意,沙盒和正式版App Store具有不同的URL,用于验证
  • 从验证响应中获取product_idexpires_date,以了解已购买的产品以及该产品是否已过期

  • 请记住,如果用户卸载并重新安装了该应用程序,则收据不会存储在设备上。然后,用户必须在应用程序从App Store服务器下载收据的情况下恢复购买。当您按下其他应用可能很熟悉的“恢复购买”按钮时,就会发生这种情况。还原只需使用 SKReceiptRefreshRequest完成。

    关于ios - 将IAP存储在UserDefaults中,这样用户无需每次按“可购买”按钮即可恢复购买,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61840552/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com