审核期间应用内购买无效标识符(在开发过程中正常运行)

时间:2018-11-29 02:45:20

标签: swift in-app-purchase swiftystorekit

我正在开发包含非消耗品的应用。我已经测试了多个沙箱帐户,并且在开发过程中一切正常。但在应用程序审核期间,productid被作为无效返回,我无法通过审核。在提交应用程序进行审核之前,我确保不消耗品处于“等待审核”状态。我也有xcode中的最新配置文件设置。我已经两次被拒绝,对于可能导致此问题的任何想法,将不胜感激。

1 个答案:

答案 0 :(得分:0)

在appDelegate中,您将以下代码放置在appDelegate中,并导入svprogresshud pod来处理错误

let PRODUCT_ID = "your itunes bundal identifire for IN app purrchase"

func fetchProductPrice(){

        InAppPurchaseManager.sharedManager.fetchProductPrice(productId: PRODUCT_ID) { (productInfo, price) in
            print("price : \(price)")

        }

    }

InAppPurchaseManager

import UIKit
import StoreKit
import SVProgressHUD


var productTitle:String = ""
var productPrice:String = ""
struct InAppMessages {

    static let kUserNotAuthorizedMessage = "You are not authorize to make purchase."
    static let kProductNotAvailableMessage = "Product not available."
    static let kErrorConnectingToServer = "Error in connecting to iTunes server."
    static let kErrorInFetchProductInfoMessage = "Failed to get product information."
    static let kProductPurchaseFailed = "Failed to purchase product.";
}
var iTuneURL = "https://buy.itunes.apple.com/verifyReceipt"
class InAppPurchaseManager: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {

    typealias PurchaseFailureHandler =  (_ error : String) -> ()
    typealias PurchaseSuccessHandler =  (_ transcation : SKPaymentTransaction) -> ()

    typealias ReceiptFailureHandler =  (_ error : String) -> ()
    typealias ReceiptSuccessHandler =  (_ receiptData : AnyObject) -> ()

    typealias RestoreSuccessHandler =  (_ restoreProductID : [String]) -> ()
    typealias RestoreFailureHandler =  (_ error : String) -> ()

    typealias ProductFetchHandler = (_ productInfo : String, _ price: String) -> ()

    static let sharedManager = InAppPurchaseManager()

    var purchaseFailureHandler : PurchaseFailureHandler?
    var purchaseSuccessHandler : PurchaseSuccessHandler?

    var receiptFailureHandler : ReceiptFailureHandler?
    var receiptSuccessHandler : ReceiptSuccessHandler?

    var restoreSuccessHandler : RestoreSuccessHandler?
    var restoreFailureHandler : RestoreFailureHandler?

    var productFetchHandler : ProductFetchHandler?

    var productToBuy : SKProduct?
    var productID : String?


   // #if DEBUG
      //  let iTuneURL = "https://sandbox.itunes.apple.com/verifyReceipt"
//    #else

//    #endif




    override init() {
        super.init()

        //Add Payment Queue Transaction Observer
        SKPaymentQueue.default().add(self)
    }


    //==========================================
    //MARK: - In App Purchase Handler Methods
    //==========================================

    func finishInterruptedTransactionsWithSuccess(_ successHandler :@escaping PurchaseSuccessHandler, _ failureHandler : @escaping PurchaseFailureHandler){

        purchaseSuccessHandler = successHandler
        purchaseFailureHandler = failureHandler

        let currentQueue : SKPaymentQueue = SKPaymentQueue.default()
        print("Transactions: \(currentQueue.transactions.count)")
        for transaction in currentQueue.transactions {

            if (transaction.transactionState == SKPaymentTransactionState.failed) {

                //possibly handle the error
                currentQueue.finishTransaction(transaction);
                 SVProgressHUD.dismiss()
                purchaseFailureHandler?(InAppMessages.kProductPurchaseFailed)
                purchaseFailureHandler = nil

            } else if (transaction.transactionState == SKPaymentTransactionState.purchased) {
                //deliver the content to the user

                currentQueue.finishTransaction(transaction)
                purchaseSuccessHandler?(transaction)
                purchaseSuccessHandler = nil
            } else {
                //handle other transaction states
                 SVProgressHUD.dismiss()
                purchaseFailureHandler?(InAppMessages.kProductPurchaseFailed)
                purchaseFailureHandler = nil
            }
        }
    }

    func canPurchase() -> Bool{
        return SKPaymentQueue.canMakePayments()
    }

    func buyProduct(){

        // show progress
        self.showMessageIndicator(message: "Please wait...")
        //AppData.showProgressGIFImage()
        let payment = SKPayment(product: self.productToBuy!)
        SKPaymentQueue.default().add(payment);
    }

    func fetchProductPrice(productId: String, fetchHandler : @escaping ProductFetchHandler){

        productFetchHandler = fetchHandler

        productID = productId

        if (SKPaymentQueue.canMakePayments())
        {
            let productID:NSSet = NSSet(object: productId);
            let productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
            productsRequest.delegate = self;
            productsRequest.start();

        }
    }

    func purchaseProductWithProductId(productId : String, fetchHandler : @escaping ProductFetchHandler ,successHandler : @escaping PurchaseSuccessHandler, failureHandler : @escaping PurchaseFailureHandler){

        purchaseSuccessHandler = successHandler
        purchaseFailureHandler = failureHandler
        productFetchHandler = fetchHandler

        productID = productId

        if (SKPaymentQueue.canMakePayments())
        {
            // show indicator

            self.showMessageIndicator(message:"Getting Product Information...")

            let productID:NSSet = NSSet(object: productId);
            let productsRequest:SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>);
            productsRequest.delegate = self;
            productsRequest.start();

        }else{

            SVProgressHUD.dismiss()
            purchaseFailureHandler?(InAppMessages.kErrorConnectingToServer)

            // show error
           // self.showErrorAlert(error: InAppMessages.kErrorConnectingToServer)
        }

    }

    func restoreProduct(successHandler : @escaping RestoreSuccessHandler, failureHandler : @escaping RestoreFailureHandler){

        // show indicator
        self.showMessageIndicator(message:"Restoring purchase...")

        restoreSuccessHandler = successHandler
        restoreFailureHandler = failureHandler

        SKPaymentQueue.default().restoreCompletedTransactions()

    }

    //==========================================
    //MARK: - SKPayment Request Delegate Methods
    //==========================================

    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {


        print("resposen invalid product \(response.invalidProductIdentifiers)")
        let count : Int = response.products.count

        if (count>0) {

            let validProduct: SKProduct = response.products[0]
            if (validProduct.productIdentifier == productID) {

                let numberFormatter = NumberFormatter()
                numberFormatter.formatterBehavior = NumberFormatter.Behavior.behavior10_4
                numberFormatter.numberStyle = NumberFormatter.Style.currency
                numberFormatter.locale = validProduct.priceLocale

                let formattedPrice = numberFormatter.string(from: validProduct.price)
                print("formattedPrice: \(formattedPrice!)")
                productPrice = formattedPrice!
                hideIndicator()
                self.productToBuy = validProduct

                productTitle = validProduct.localizedTitle
                //let productMessage = "Do you want to buy \(validProduct.localizedTitle) at \(formattedPrice!) amount?"
               let productMessage = " Want to access premium content for only \(formattedPrice!) a month?"
                productFetchHandler?(productMessage, formattedPrice!)

                // buy product
                //buyProduct(product: validProduct);
            }
            else {
                SVProgressHUD.dismiss()
                print(validProduct.productIdentifier)
                purchaseFailureHandler?(InAppMessages.kProductNotAvailableMessage)
                //self.showErrorAlert(error: InAppMessages.kProductNotAvailableMessage)
            }

        } else {
            SVProgressHUD.dismiss()
            purchaseFailureHandler?(InAppMessages.kProductNotAvailableMessage)

            // show error
           // self.showErrorAlert(error: InAppMessages.kProductNotAvailableMessage)
        }

    }

    func request(_ request: SKRequest, didFailWithError error: Error) {

        print("Error Fetching product information : \(error.localizedDescription)");
        SVProgressHUD.dismiss()
        purchaseFailureHandler?(InAppMessages.kErrorInFetchProductInfoMessage)

        // show error alert
       // self.showErrorAlert(error: InAppMessages.kErrorInFetchProductInfoMessage)
    }

    //============================================
    //MARK: - SKPaymentTransactionObserver Methods
    //============================================

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]){

        //print("Received Payment Transaction Response from Apple");

        for transaction in transactions {

            switch transaction.transactionState {

            case .purchased:

                // hide indicator
                self.hideIndicator()

                //print("Product Purchased: \(transaction.transactionIdentifier)")
                SKPaymentQueue.default().finishTransaction(transaction);

                self.purchaseSuccessHandler?(transaction)
                self.purchaseSuccessHandler = nil

                //To Get Receipt from Bundle

                //                let mainBundle = Bundle.main as Bundle;
                //                let receiptUrl = mainBundle.appStoreReceiptURL;
                //
                //                let data = NSData(contentsOf: receiptUrl!);
                //
                //                if(data != nil){
                //
                //                    let base64String = data!.base64EncodedString()
                //
                //                    // verify payment receipt
                //                    verifyPaymentReceipt(base64EncodedString: base64String)
                //                }
                break;

            case .failed:
                SVProgressHUD.dismiss()
                purchaseFailureHandler?(InAppMessages.kProductPurchaseFailed)
                purchaseFailureHandler = nil

                SKPaymentQueue.default().finishTransaction(transaction);
                 SVProgressHUD.dismiss()
               //self.showErrorAlert(error: InAppMessages.kProductPurchaseFailed)

                break;

            case .purchasing:

                self.showMessageIndicator(message: "Please wait \ntransaction in progress...")

                print("Transaction is being added to the server queue.");

            case .restored:

                SKPaymentQueue.default().finishTransaction(transaction);
                print("Already Purchased");


            case .deferred:

                print("The transaction is in the queue, but its final status is pending external action.");
            }
        }
    }


    func paymentQueue(_ queue: SKPaymentQueue, removedTransactions transactions: [SKPaymentTransaction]) {
    }

    func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {

        print("Restore Purchase done")

        var productIds = [String]()
        for transcation in queue.transactions{
            productIds.append(transcation.payment.productIdentifier)
        }

        hideIndicator()
        self.restoreSuccessHandler?(productIds)
        self.restoreSuccessHandler = nil
        self.restoreFailureHandler = nil
    }

    func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error){

        self.restoreFailureHandler?(error.localizedDescription)
        self.restoreSuccessHandler = nil
        self.restoreFailureHandler = nil
    }

    //============================================
    //MARK: - Verify Receipt
    //============================================

    func verifyPaymentReceipt(base64EncodedString : String,ReceiptValidationPassword : String, receiptSuccess : ReceiptSuccessHandler?, receiptFailure : ReceiptFailureHandler?){

        receiptSuccessHandler = receiptSuccess
        receiptFailureHandler = receiptFailure

        self.showMessageIndicator(message: "Verifying payment...")

        // Create the JSON object that describes the request
        let requestContents  = NSMutableDictionary();
        requestContents.setObject(base64EncodedString, forKey: "receipt-data" as NSCopying);
        requestContents.setObject(ReceiptValidationPassword, forKey: "password" as NSCopying);

        var requestData : NSData?

        do{
            requestData = try JSONSerialization.data(withJSONObject: requestContents, options: JSONSerialization.WritingOptions()) as NSData?;
        }catch{
            NSLog("Error in json data creation at verifyPaymentReceipt");
        }
        StoreDataCheck(requestData!)

    }

    func StoreDataCheck(_ requestData:NSData)
    {
        // Create a POST request with the receipt data.
        let storeURL = NSURL(string: iTuneURL);
        var storeRequest = URLRequest(url: storeURL! as URL);
        storeRequest.httpMethod = "POST";
        storeRequest.httpBody = requestData as Data?;

        let session = URLSession(configuration: URLSessionConfiguration.default)
        let dataTask = session.dataTask(with: storeRequest) { (responseData, response, error) in

           // self.hideIndicator()
            if (error == nil){

                var jsonResponse: NSDictionary = NSDictionary()
                do{

                    jsonResponse = try JSONSerialization.jsonObject(with: responseData!, options: JSONSerialization.ReadingOptions.allowFragments) as! NSDictionary
                    if jsonResponse.value(forKey: "status") as? Int == 21007
                    {

                        iTuneURL = "https://sandbox.itunes.apple.com/verifyReceipt"
                        self.StoreDataCheck(requestData)

                    }
                    else
                    {
                        self.receiptSuccessHandler?(jsonResponse)
                    }


                }catch{
                    self.receiptFailureHandler?("Parsing issue : verifyPaymentReceipt")
                }
            }
            else{
                self.receiptFailureHandler?(error!.localizedDescription)
            }
        }
        dataTask.resume()
    }


    //============================================
    //MARK: - Alert / Activity Indicator
    //============================================

    func showIndicator() {

        SVProgressHUD.show()
    }

    func showMessageIndicator(message: String) {
        hideIndicator()

        SVProgressHUD.show(withStatus: message)
    }

    func hideIndicator() {
        SVProgressHUD.dismiss()
    }

    func showErrorAlert(error: String){

        hideIndicator()

        SVProgressHUD.showError(withStatus: error)


    }

    func showWithStatus(status: String){

        hideIndicator()

        SVProgressHUD.showInfo(withStatus: status)

    }
}

并将此代码放入您的按钮操作中

func InApp()
    {


          SVProgressHUD.show()

        if InAppPurchaseManager.sharedManager.canPurchase(){

            InAppPurchaseManager.sharedManager.purchaseProductWithProductId(productId: PRODUCT_ID, fetchHandler: { (productInfoMessage, price) in
                SVProgressHUD.dismiss()

                            InAppPurchaseManager.sharedManager.buyProduct()
                      print(productInfoMessage)                
            }, successHandler: { (transaction) in


                self.purchaseSuccessful(transaction)
                transectionID = transaction.transactionIdentifier!


            }, failureHandler: { (error) in
                print(error)
                   InAppPurchaseManager.sharedManager.hideIndicator()
              )
                InAppPurchaseManager.sharedManager.hideIndicator()
            })

        }else{

           print( "Device is not able to make purchase. \n Please enable it from Settings -> General -> Restrictions -> In-App Purchases")
        }
    }

    func purchaseSuccessful(_ transaction : SKPaymentTransaction) {

        do {

            if let receiptURL = Bundle.main.appStoreReceiptURL {
                let data = try Data(contentsOf: receiptURL)
                if data != nil {
                    InAppPurchaseManager.sharedManager.verifyPaymentReceipt(base64EncodedString: data.base64EncodedString(),
                                                                            ReceiptValidationPassword: inAppPassword,
                                                                            receiptSuccess: { (response) in
                                                                                print("response \(response)")

                                                                                if let receipt = response as? NSDictionary {
                                                                                    if let receiptInfo = receipt.object(forKey: "receipt"  as NSCopying) as? NSDictionary{


                                                        let strOriginalPurchaseTime = receiptInfo.object(forKey: "receipt_creation_date_ms" as NSCopying) as! String
                                                        let timeInMS = TimeInterval(Double(strOriginalPurchaseTime)!)
                                                        let date = Date(timeIntervalSince1970: timeInMS / 1000)

                                                        purchaseDate  = "\(date)"
                                                        print("date of purchase \(date)")

                                                                                        }
                                                                                }
                    }, receiptFailure: { (error) in
                        print("error \(error)")
                                          })
                }

            }

        }catch {

        }

    }