为什么我的应用程序因应用程序内购买而被拒绝?

时间:2018-10-06 17:57:22

标签: ios swift in-app-purchase

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

在沙盒中对它们进行自我测试后,一切正常。

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

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

  

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

     

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

     

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

     

后续步骤

     

验证服务器上的收据时,您的服务器需要能够   处理生产签名的应用程序,从苹果公司获得收据   测试环境。推荐的方法适合您的生产   服务器始终根据生产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"
            }
        }
    }

2 个答案:

答案 0 :(得分:2)

对于苹果,应用程序审查非常严格。从经验上来讲,我遇到过很多次这个问题。在执行givePurchasedProduct函数之前,您的代码对我来说似乎还不错。

好的,我注意到了:

  1. 您的应用处理付款,如果没有任何问题,我们将获得return "purchased"
  2. 如果案例为case .purchased:,则我们调用GivePurchasedProduct

关于您的功能。您可以分开购买,以查看是 Zap 购买还是要删除广告

但是。这行让我感到困惑-最近介绍range时为什么要使用contains

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)")
    }
}

现在,现在。对审阅者,购买的内容没有交付。因此,他们认为这是购买验证。

您如何验证购买?提供内容?请更新您的问题。我敢肯定我会帮忙的

祝你好运

答案 1 :(得分:0)

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

Apple有2个用于InApp购买的环境-测试和生产。两种环境的行为相同。当您在iPhone上运行该应用以进行质量检查或调试时进行测试时,该应用会连接到“测试”环境。使用测试环境时不会向您收取实际费用。但是生成的收据与实际生产环境中的收据几乎相同

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

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