gpt4 book ai didi

ios - InApp 购买耗材服务器验证设置

转载 作者:行者123 更新时间:2023-11-28 07:19:59 27 4
gpt4 key购买 nike

我正在使用 SwiftyStoreKit 作为小费 jar 的 InApp Purchase Consumable。一切都适用于测试,但根据 this answer并且评论服务器端验证不是必需的,但建议这样做。答案指出 “消耗品、非消耗品和订阅容易受到欺诈攻击。通常是通过 iap 黑客或网络欺骗。验证收据可以缓解这个问题”

1- 如果用户 A 向我发送小费,如果一切都通过 Apple,攻击者怎么可能拦截该小费并拿走钱?

2- 我需要设置一个 Heroku 实例还是使用其他东西来进行服务器验证?我在上面找不到任何东西。我假设我需要在 if product.needsFinishTransaction { SwiftyStoreKit.finishTransaction(product.transaction) } 下面的 success case 中添加服务器端代码,但我没有从那时起我就不知道如何设置服务器了。

SwiftyStoreKit.purchaseProduct(product, quantity: 1, atomically: true) { result in

switch result {
case .success(let product):
// fetch content from your server, then:
if product.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(product.transaction)
}
print("Purchase Success: \(product.productId)")
// failed cases ...
}
}

代码如下:

应用委托(delegate):

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

SwiftyStoreKit.completeTransactions(atomically: true) { purchases in
for purchase in purchases {
switch purchase.transaction.transactionState {
case .purchased, .restored:
if purchase.needsFinishTransaction {
// Deliver content from server, then:
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
// Unlock content
case .failed, .purchasing, .deferred:
break // do nothing
@unknown default:
break
}
}
}
}

TipJarVC。购买是在 collectionView 的 didSelect item 中进行的:

var dataSource = [Tip]()
var sharedSecret = appStoreConnectSecretKey

let inAppProductIds = ["com.myCo.myAppName.firstTip", // 0.99
"com.myCo.myAppName.secondTip", // 9.99 ]

override func viewDidLoad() {
super.viewDidLoad()

getInAppPurchaseAmounts()
}

func getInAppPurchaseAmounts() {

// show spinner

let dispatchGroup = DispatchGroup()

for productId in inAppProductIds {

dispatchGroup.enter()

SwiftyStoreKit.retrieveProductsInfo([productId]) { [weak self](result) in
if let product = result.retrievedProducts.first {
let priceString = product.localizedPrice!
print("Product: \(product.localizedDescription), price: \(priceString)")

let tip = Tip(displayName: product.description,
description: product.localizedDescription,
productId: productId
price: priceString)


self?.addTipToDataSource(tip)

if let sharedSecret = self?.sharedSecret {

self?.verifyPurchase(with: productId, sharedSecret: sharedSecret)
}
dispatchGroup.leave()

} else if let invalidProductId = result.invalidProductIDs.first {
print("Invalid product identifier: \(invalidProductId)")
dispatchGroup.leave()

} else {
print("Error: \(String(describing: result.error))")
dispatchGroup.leave()
}
}
}

dispatchGroup.notify(queue: .global(qos: .background)) { [weak self] in
DispatchQueue.main.async { [weak self] in

// removeSpinnerAndReloadData()
}
}
}

func verifyPurchase(with productId: String, sharedSecret: String) {

let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: sharedSecret)
SwiftyStoreKit.verifyReceipt(using: appleValidator) { result in
switch result {
case .success(let receipt):
let productId = productId
// Verify the purchase of Consumable or NonConsumable
let purchaseResult = SwiftyStoreKit.verifyPurchase(
productId: productId,
inReceipt: receipt)

switch purchaseResult {
case .purchased(let receiptItem):
print("\(productId) is purchased: \(receiptItem)")
case .notPurchased:
print("The user has never purchased \(productId)")
}
case .error(let error):
print("Receipt verification failed: \(error)")
}
}
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? TipCell else { return }
guard let indexPath = collectionView.indexPath(for: cell) else { return }

let tip = dataSource[indexPath.item]

purchaseProduct(with: tip.productId)
}

func purchaseProduct(with productId: String) {

SwiftyStoreKit.retrieveProductsInfo([productId]) { result in
if let product = result.retrievedProducts.first {
SwiftyStoreKit.purchaseProduct(product, quantity: 1, atomically: true) { result in

switch result {
case .success(let product):
// fetch content from your server, then:
if product.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(product.transaction)
}
print("Purchase Success: \(product.productId)")
case .error(let error):
switch error.code {
case .unknown:
print("Unknown error. Please contact support")
case .clientInvalid:
print("Not allowed to make the payment")
case .paymentCancelled:
print("Payment cancelled")
case .paymentInvalid:
print("The purchase identifier was invalid")
case .paymentNotAllowed:
print("The device is not allowed to make the payment")
case .storeProductNotAvailable:
print("The product is not available in the current storefront")
case .cloudServicePermissionDenied:
print("Access to cloud service information is not allowed")
case .cloudServiceNetworkConnectionFailed:
print("Could not connect to the network")
case .cloudServiceRevoked:
print("User has revoked permission to use this cloud service")
default:
print((error as NSError).localizedDescription)
}
}
}
}
}
}

最佳答案

您不必害怕攻击者——因为它只与越狱设备有关,他们唯一能做的就是免费使用您的付费功能。而且没有人能拿走这笔钱。一切都很安全。

如果您只想进行 IAP 购买,您可以使用 SwiftyStoreKit

您可以阅读 this article来 self 们关于收据验证的博客。

关于ios - InApp 购买耗材服务器验证设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58490327/

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