在 appstoreconnect 中无法选择应用内购买
我的新应用程序有四个应用程序内购买(消耗品),我使用这些 IAP 提交了第一个版本。这些 IAP 被标记为“准备审核”。然而,该应用程序由于另一个原因被拒绝,当我上传新版本时,我无法再在应用程序详细信息页面中选择这些 IAP,即使它们仍然“准备审核”: 应用详细信息页面的屏幕截图
因此,在重新提交新版本的应用进行审核后,我得到了本次拒签信息:
我们发现,在通过 Wi-Fi 运行 iOS 15.4 的 iPad 上审核时,您的应用内购买产品出现了一个或多个错误。
具体来说,我们无法购买应用内购买项目。按钮对点击没有反应
后续步骤
在服务器上验证收据时,您的服务器需要能够处理从 Apple 测试环境获取收据的生产签名应用程序。建议的方法是让您的生产服务器始终首先根据生产 App Store 验证收据。如果验证失败并显示错误代码“生产中使用的沙盒收据”,您应该改为针对测试环境进行验证。
我之前在 Testflight 上测试了所有内容,所有 IAP 都工作正常。我知道在提交带有 IAP 的应用程序之前,必须在应用程序详细信息页面上选择这些购买,所以我很好奇为什么我无法选择它们以及这是否导致了问题。
当应用程序启动时,在 AppDelegate 中,我获取产品:IAPManager.shared.fetchProducts()
,IAPManager 的代码如下:
final class IAPManager: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
static let shared = IAPManager()
var products = [SKProduct]()
enum Product: String, CaseIterable {
case firstIdentifier = "com.fahrprueferCreate.tokens_1_1000"
case secondIdentifier = "com.FahrprueferCreate.tokens_5_4000"
case thirdIdentifier = "com.FahrprueferCreate.tokens_10_8000"
case fourthIdentifier = "com.FahrprueferCreate.tokens_20_15000"
var count: Int {
switch self {
case .firstIdentifier:
return 1
case .secondIdentifier:
return 5
case .thirdIdentifier:
return 10
case .fourthIdentifier:
return 20
}
}
}
private var completion: ((Int) -> Void)?
// Fetch Product Objects from Apple
func fetchProducts() {
let request = SKProductsRequest(productIdentifiers: Set(Product.allCases.compactMap({ $0.rawValue})))
request.delegate = self
request.start()
}
// Prompt a product payment transaction
public func purchase(product: Product, completion: @escaping ((Int) -> Void)) {
guard SKPaymentQueue.canMakePayments() else {
// Show some error here
return
}
guard let storeKitProduct = products.first(where: { $0.productIdentifier == product.rawValue }) else {
return
}
self.completion = completion
let payment = SKPayment(product: storeKitProduct)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment)
}
// Observe the transaction state
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
transactions.forEach({ transaction in
switch transaction.transactionState {
case.purchasing:
break
case .purchased:
if let product = Product(rawValue: transaction.payment.productIdentifier) {
completion?(product.count)
}
SKPaymentQueue.default().finishTransaction(transaction)
SKPaymentQueue.default().remove(self)
break
case .restored:
break
case .failed:
break
case .deferred:
break
@unknown default:
break
}
})
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
self.products = response.products
print("products: ", response.products)
}
func request(_ request: SKRequest, didFailWithError error: Error) {
guard request is SKProductsRequest else {
return
}
print("Product fetch request failed")
}
}
My new app has four in app purchases (consumables) and I submitted the first version with these IAPs. These IAP's were marked as "Ready for Review". However, the app got rejected due to another reason, and when I uploaded a new build, I couldn't select these IAP's anymore in the app details page, even though they're still "Ready for Review":
screenshot of the app details page
So after resubmitting a new version of the app for review, I got this rejection information:
We found that your in-app purchase products exhibited one or more bugs when reviewed on iPad running iOS 15.4 on Wi-Fi.
Specifically, we were not able to buy the in app purchases. The buttons did not react to taps
Next Steps
When validating receipts on your server, your server needs to be able to handle a production-signed app getting its receipts from Apple’s test environment. The recommended approach is for your production server to always validate receipts against the production App Store first. If validation fails with the error code "Sandbox receipt used in production," you should validate against the test environment instead.
I tested everything on Testflight before and all the IAP's were working fine. I know that prior to submitting an app with IAP's, these purchases have to be selected on the app details page, so I'm curious why I can't select them and if that's causing the issue.
Right when the app launches, in the AppDelegate, I fetch the products: IAPManager.shared.fetchProducts()
and the code for the IAPManager is as follows:
final class IAPManager: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
static let shared = IAPManager()
var products = [SKProduct]()
enum Product: String, CaseIterable {
case firstIdentifier = "com.fahrprueferCreate.tokens_1_1000"
case secondIdentifier = "com.FahrprueferCreate.tokens_5_4000"
case thirdIdentifier = "com.FahrprueferCreate.tokens_10_8000"
case fourthIdentifier = "com.FahrprueferCreate.tokens_20_15000"
var count: Int {
switch self {
case .firstIdentifier:
return 1
case .secondIdentifier:
return 5
case .thirdIdentifier:
return 10
case .fourthIdentifier:
return 20
}
}
}
private var completion: ((Int) -> Void)?
// Fetch Product Objects from Apple
func fetchProducts() {
let request = SKProductsRequest(productIdentifiers: Set(Product.allCases.compactMap({ $0.rawValue})))
request.delegate = self
request.start()
}
// Prompt a product payment transaction
public func purchase(product: Product, completion: @escaping ((Int) -> Void)) {
guard SKPaymentQueue.canMakePayments() else {
// Show some error here
return
}
guard let storeKitProduct = products.first(where: { $0.productIdentifier == product.rawValue }) else {
return
}
self.completion = completion
let payment = SKPayment(product: storeKitProduct)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment)
}
// Observe the transaction state
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
transactions.forEach({ transaction in
switch transaction.transactionState {
case.purchasing:
break
case .purchased:
if let product = Product(rawValue: transaction.payment.productIdentifier) {
completion?(product.count)
}
SKPaymentQueue.default().finishTransaction(transaction)
SKPaymentQueue.default().remove(self)
break
case .restored:
break
case .failed:
break
case .deferred:
break
@unknown default:
break
}
})
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
self.products = response.products
print("products: ", response.products)
}
func request(_ request: SKRequest, didFailWithError error: Error) {
guard request is SKProductsRequest else {
return
}
print("Product fetch request failed")
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论