【问题标题】:Why is my App Rejected for In-App Purchases?为什么我的应用因应用内购买而被拒绝?
【发布时间】:2018-10-06 17:57:21
【问题描述】:

您好,我正在 App Store 上发布我的应用,因为他们一直坚持我的应用内购买设置不正确。

在沙盒中亲自测试后,一切正常。

这是他们发给我的消息,我在下面粘贴了我的代码。

感谢您抽出宝贵时间帮助我!

指南 2.1 - 性能 - 应用完整性

我们发现您的应用内购买产品存在一个或多个错误 在通过 Wi-Fi 运行 iOS 12 的 iPhone 和 iPad 上进行审核时。

具体来说,您的应用内购买按钮不起作用。

后续步骤

在您的服务器上验证收据时,您的服务器需要能够 处理从 Apple 获取收据的生产签名应用程序 测试环境。推荐的方法适用于您的生产 服务器始终根据生产 App Store 验证收据 第一的。如果验证失败并显示错误代码“使用沙盒收据 在生产中,”您应该针对测试环境进行验证 而是。

class IAPService: NSObject {
    private override init() {}
    static let shared = IAPService()

    var products = [SKProduct]()
    let paymentQueue = SKPaymentQueue.default()

    func getProducts() {
        let products: Set = [IAPProduct.consumable.rawValue,
                             IAPProduct.nonConsumable.rawValue]
        let request = SKProductsRequest(productIdentifiers: products)
        request.delegate = self
        request.start()
        paymentQueue.add(self)
    }

    func purchase(product: IAPProduct) {


        for p in products {
            if p.productIdentifier == product.rawValue {
                let payment = SKPayment(product: p)
                paymentQueue.add(payment)
                print("Adding product to payment queue")
            }
        }
      }

    func restorePurchase() {
        print("Restoring purchases")
        paymentQueue.restoreCompletedTransactions()
    }


    func givePurchasedProduct(productID: String) {

        if productID.range(of: "Zap") != nil {

            NotificationCenter.default.post(name: Notification.Name.init("zapPurchased"), object: nil)

        } else if productID.range(of: "Ads") != nil {

            NotificationCenter.default.post(name: Notification.Name.init("noAdsPurchased"), object: nil)

        }
    }
 }
extension IAPService: SKProductsRequestDelegate {

    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        self.products = response.products
        for product in response.products {
            print(product.localizedTitle)
        }
    }

}
    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, .deferred: break // do nothing
                case .purchased:
                    queue.finishTransaction(transaction)
                    givePurchasedProduct(productID: transaction.payment.productIdentifier)
                case .restored:
                    self.restorePurchase()
                    queue.finishTransaction(transaction)

               case .failed:
                    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"
            }
        }
    }

【问题讨论】:

  • “您的应用内购买按钮不起作用” 那么响应按钮的代码在哪里?他们告诉过你,这就是问题所在。 — 另外,单例如何充当 SKPaymentTransactionObserver?你需要展示更多的架构来证明这是可能的。
  • 您的事务观察器中的逻辑也不正确;在您成功坚持购买之前,您正在致电finishTransaction。在确认您的应用已识别购买之前,您不得完成交易。由于您只是触发通知,因此您无法确定是否发生了这种情况。此外,您恢复完成的事务将创建一个无限循环。在您的事务观察器中,restored 状态应与.purchased 状态相同。
  • @matt 为什么事务观察者不能是单例(除了不使用单例的一般原因)?事务观察者实际上需要与应用程序本身相同的生命周期。如果我不使用单例,我将对象实例设为应用委托的属性,效果类似
  • @Paulw11 我毫不怀疑 you 早早地创建了这个单例并将其分配给一个持久变量/属性并将其设置为观察者。我没有理由认为 OP 也在做同样的事情。我要求OP向我展示证据,仅此而已。代码不起作用,我为什么要把任何事情视为理所当然?
  • 好的,我同意。我们需要知道如何以及何时实例化它们的对象。在阅读您的评论时,我认为您是在一般情况下向 Singleton 观察者提出问题,而不是围绕此代码的实例化的细节。

标签: ios swift in-app-purchase


【解决方案1】:

对于 Apple,应用审查非常严格。从经验上讲,我遇到过很多次这个问题。你的代码对我来说似乎很好,直到它进入 givePurchasedProduct 函数。

好的,我注意到了:

  1. 您的应用会处理付款,如果没有问题,我们会收到 return "purchased"
  2. 如果案例是case .purchased:,那么我们调用 givePurchasedProduct

关于你的功能。您将购买分开,看看它是 Zap 购买还是要删除 广告

但是。这条线让我很困惑——当最近介绍了contains 时,你为什么要使用range

if productID.contains("Zap") {
     // No Zapp? it has to be Ads then
     NotificationCenter.default.post(name: Notification.Name.init("zapPurchased"), object: nil)
} else {
     NotificationCenter.default.post(name: Notification.Name.init("noAdsPurchased"), object: nil)   
}

旁注。你可能忘记了:

  1. import Foundation
  2. 我不知道通知观察者背后的原因,因为代码不包括在内。但。它没有交付

还有更多。 Receipt Validating 令人头疼,但在需要时。这是您的应用程序的放松和更多安全性。

如果您正在验证收据。这些问题及其答案对我帮助很大。请看:

奖金。与SwiftyStoreKit。收据验证就像点击一个按钮:

使用此方法(可选)刷新收据并一步执行验证。

let appleValidator = AppleReceiptValidator(service: .production, sharedSecret: "your-shared-secret")
SwiftyStoreKit.verifyReceipt(using: appleValidator, forceRefresh: false) { result in
    switch result {
    case .success(let receipt):
        print("Verify receipt success: \(receipt)")
    case .error(let error):
        print("Verify receipt failed: \(error)")
    }
}

另一方面。对审阅者购买的内容没有交付。所以他们认为这是购买验证。

您如何验证购买?交付内容?请更新您的问题。我相信我会有所帮助

祝你好运

【讨论】:

  • 您好,非常感谢您抽出宝贵时间查看我的问题!我一定会试试这个,并随时通知你。如果我的代码有时看起来有点奇怪,我深表歉意,我是自学的,所以我按照教程进行操作。
  • @PatTrudel。我可以等
  • 您好,我实际上并没有验证我的收据,因为我拥有的唯一 IAP 是消耗品和非消耗品。
  • Apple 再次拒绝了我的应用,因为根据您的建议修复了我的代码,他们仍然坚持认为我的 IAP 不起作用。
  • 我已经在我自己的设备和使用 TestFlight 的朋友设备上测试了我所有的应用内购买,但是一旦在 Apple 上,它似乎对他们不起作用,我该怎么办?我真的在这里绝望了.....
【解决方案2】:

我认为您的 iOS 代码没有问题。从 Apple 的回复中,他们说,您的服务器指向 Apple InApp 购买的生产环境,并验证从 App 内使用的 Apple InApp 购买测试环境收到的收据。

Apple 有 2 个用于 InApp 购买的环境 - 测试和生产。两种环境的行为相同。当您在 iPhone 上运行应用程序以由 QA 进行测试或在调试时,它会连接到测试环境。使用测试环境时,您不会被实际收费。但生成的收据与实际生产环境几乎相同

现在,当您将应用程序提交到商店时,它会自动从生产环境进行购买。向用户收费并生成真实收据。

我认为您的应用程序正在将这些收据发送到服务器,并且您的服务器使用错误的 InApp 服务器环境来验证收据。 在您的服务器上,确保根据您的 InApp 购买收据正确选择 Apple InApp 购买环境 URL。如果您或您的团队正在测试应用程序,您的服务器必须使用测试 URL,当应用程序提交生产时,您的服务器必须使用 InApp Purchase 的生产 URL。

【讨论】:

  • 您好,感谢您抽出宝贵时间回答!不幸的是,我认为这不适用于我,因为我没有服务器,这个应用程序是一个不需要后端的小游戏
  • 那么,你是在 iOS App 本身中处理收据验证吗?
  • 我不知道该怎么做,
  • 您能帮我找到 Swift 的指南吗?
猜你喜欢
  • 2018-10-18
  • 2017-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-28
  • 2015-08-06
  • 2015-06-04
相关资源
最近更新 更多