- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在使用 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/
我目前正在开发一款将在 Android 电子市场上发布的应用程序。我如何在我的 Cocos2x 项目中实现用于 Android Market 应用内计费的 Google 代码? 将不胜感激详细的解释(
我有一个在 Play 商店发布的 Android 应用程序。我正在尝试在 App 更新中实现并使用 android 内部轨道共享对其进行测试。 为了在内部轨道上分享,我尝试了关注,一切都给了我相同的结
这可能是一个愚蠢的问题,但我一直找不到答案。应用内购买应存储在设备上的哪个位置?它们是否下载到 bundle 中? 最佳答案 你必须自己存储它们。为了简单起见,我会使用 NSUserDefaults。
我正在尝试执行 inaAppPurchases 并使用以下代码 NSSet *myProductIdentifiers = [NSSet setWithObjects:
我想实现每周自动扣除金额的应用内购买。用户不必一次又一次地输入凭据。它只是通知用户并扣除金额。 喜欢应用程序中的新闻信函功能。每周扣除特定金额。它会要求一次 inapp 凭据,然后它会自动扣除。 我听
我正在使用我自己的服务器验证 App Store 的收据以进行自动续订订阅。并返回状态、收据、latest_receipt、latest_receipt_info、latest_expired_rec
好吧,在你们大发雷霆说它是重复的之前,我已经尝试了互联网上的所有其他答案,但我仍然遇到这个错误。 注意:我使用的是应用内 V3 API。 首先,我创建了应用内产品(我的控制台中已有一个 apk 草稿文
好的,我正在为我的应用实现应用内订阅。循环周期为每月。一切正常 - 我可以从我的测试帐户订阅,正在从购买状态 API 获取信息。 我从购买状态 API 得到的响应是: { "kind": "andro
我正在使用 SwiftyStoreKit 作为小费 jar 的 InApp Purchase Consumable。一切都适用于测试,但根据 this answer并且评论服务器端验证不是必需的,但建
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
是否可以从应用本身获取以本地货币表示的产品价格。例如,如果我通过 Google Play In App billing 以 1 美元的价格销售 Product1。来自英国的客户点击按钮购买产品,Goo
我已经在我的应用程序中实现了应用内购买,但有时它会给我 NPE,下面是堆栈跟踪。如果有人感兴趣,我也可以发布代码。 java.lang.RuntimeException: Unable to star
我已经在一个应用中实现了应用计费,现在我想进一步保护它。阅读它声明的开发人员 Material : In addition to running an obfuscation program, we
当 Firebase 中发生自定义事件时,我们如何测试应用内消息?我的事件在 DebugView firebase 控制台中显示,但在我的应用程序中不显示任何消息对话框仅在应用程序启动时以及我在 Fi
这个问题在这里已经有了答案: How to share in-app-purchases between two Android apps (2 个回答) 4年前关闭。 背景:我曾经在 Play St
我有一个应用程序,因为我需要为Inapp购买添加大约100种产品,我知道所有过程都是一步一步地手动完成的,但是我们还有其他方法可以动态地将许多产品添加为一堆吗? 可能是通过一些xls格式的文件等。 因
我有一个移动应用,其中包含一些用户可以购买的应用内商品。一旦用户购买了一些应用内产品,应用就会将 JSON 收据发送到我的服务器,以便根据我的 Google 开发者公钥(存储在服务器中)进行在线验证。
我正在为应用内购买实现 anjlab 库。我尝试购买商品。有时我收到错误。错误代码为 102。如果我再次尝试 t0 购买,则购买成功且不显示 google 购买对话框。我在关注。 https://gi
使用 implementation 'com.google.firebase:firebase-analytics:17.2.1' implementation 'com.google.firebas
我的应用目前已上线。在提交过程中,我没有检查 inapp 购买,也没有提交审核。现在该应用程序已上线,但我无法提交应用内购买,但按钮已禁用。如何在不重新上传新版本的情况下再次提交 inapp 购买。任
我是一名优秀的程序员,十分优秀!