SKProductsRequest返回0个产品

时间:2018-01-03 02:12:01

标签: ios in-app-purchase itunesconnect

我正在尝试进行IAP,但出于某种原因,我的SKProductsRequest返回0个产品。

- 测试产品已添加到iTunes正确连接

- 填写银行和征税信息

- 产品的套装ID与应用套装ID

相匹配

- 我已经等了两天才能通过服务器进行处理

我使用这个youtube教程来构建应用程序: https://www.youtube.com/watch?v=zRrs7O5yjKI

以下是代码:

import UIKit
import StoreKit

class ViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {

    @IBOutlet weak var lblAd: UILabel!
    @IBOutlet weak var lblCoinAmount: UILabel!

    @IBOutlet weak var outRemoveAds: UIButton!
    @IBOutlet weak var outAddCoins: UIButton!
    @IBOutlet weak var outRestorePurchases: UIButton!



    var coins = 50

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        outRemoveAds.isEnabled = false
        outAddCoins.isEnabled = false
        outRestorePurchases.isEnabled = false

        if(SKPaymentQueue.canMakePayments()) {
            print("IAP is enabled, loading")
            let productID: NSSet = NSSet(objects: "com.IAPTesters.10Dolla", "com.IAPTesters.RemoveAds")
            let request: SKProductsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
            request.delegate = self
            request.start()
        } else {
            print("please enable IAPS")
        }
    }
    @IBAction func btnRemoveAds(_ sender: Any) {
        print("rem ads")
        for product in list {
            let prodID = product.productIdentifier
            if(prodID == "com.IAPTesters.RemoveAds") {
                p = product
                buyProduct()
            }
        }
    }

    @IBAction func btnAddCoins(_ sender: Any) {
        for product in list {
            let prodID = product.productIdentifier
            if(prodID == "com.IAPTesters.10Dolla") {
                p = product
                buyProduct()
            }
        }
    }

    @IBAction func btnRestorePurchases(_ sender: Any) {
        SKPaymentQueue.default().add(self)
        SKPaymentQueue.default().restoreCompletedTransactions()
    }

    func buyProduct() {
        print("buy " + p.productIdentifier)
        let pay = SKPayment(product: p)
        SKPaymentQueue.default().add(self)
        SKPaymentQueue.default().add(pay as SKPayment)
    }

    func removeAds() {
        lblAd.removeFromSuperview()
    }

    func addCoins() {
        coins += 50
        lblCoinAmount.text = "\(coins)"
    }

    var list = [SKProduct]()
    var p = SKProduct()

    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        print("product request")
        let myProduct = response.products
        for product in myProduct {
            print("product added")
            print(product.productIdentifier)
            print(product.localizedTitle)
            print(product.localizedDescription)
            print(product.price)

            list.append(product)
        }

        outRemoveAds.isEnabled = true
        outAddCoins.isEnabled = true
        outRestorePurchases.isEnabled = true
    }

    func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
        print("transactions restored")
        for transaction in queue.transactions {
            let t: SKPaymentTransaction = transaction
            let prodID = t.payment.productIdentifier as String

            switch prodID {
            case "com.IAPTesters.RemoveAds":
                print("remove ads")
                removeAds()
            case "com.IAPTesters.10Dolla":
                print("add coins to account")
                addCoins()
            default:
                print("IAP not found")
            }
        }
    }

    func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
        print("add payment")

        for transaction: AnyObject in transactions {
            let trans = transaction as! SKPaymentTransaction
            print(trans.error)
            switch trans.transactionState {
            case .purchased:
                print("buy ok, unlock IAP HERE")
                print(p.productIdentifier)

                let prodID = p.productIdentifier
                switch prodID {
                case "com.IAPTesters.RemoveAds":
                    print("remove ads")
                    removeAds()
                case "com.IAPTesters.10Dolla":
                    print("add coins to account")
                    addCoins()
                default:
                    print("IAP not found")
                }
                queue.finishTransaction(trans)
            case .failed:
                print("buy error")
                queue.finishTransaction(trans)
                break
            default:
                print("Default")
                break
            }
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

当您运行应用程序时,它将打印“IAP已启用,正在加载”而不是“产品请求”,但没有其他内容。

如果我在productsRequest函数中打印response.invalidProductIdentifiers,它将返回我的产品:["com.IAPTesters.RemoveAds", "com.IAPTesters.10Dolla"]

提前感谢您的帮助

3 个答案:

答案 0 :(得分:1)

如果您参考SKProductsRequest documentation,您会看到:

  

注意

     

确保对请求对象保持强引用;否则,系统可能会在请求完成之前解除分配请求。

您的SKProductsRequest实例是viewDidLoad中的本地常量。一旦viewDidLoad退出,这将被解除分配,并且由于产品请求将异步完成,这将在请求完成之前完成,因此您将永远不会收到回电。

您应该将SKProductsRequest保留在属性中,以便不会释放它。

class ViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {

    @IBOutlet weak var lblAd: UILabel!
    @IBOutlet weak var lblCoinAmount: UILabel!

    @IBOutlet weak var outRemoveAds: UIButton!
    @IBOutlet weak var outAddCoins: UIButton!
    @IBOutlet weak var outRestorePurchases: UIButton!

    var productsRequest: SKProductsRequest?

    var coins = 50

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        outRemoveAds.isEnabled = false
        outAddCoins.isEnabled = false
        outRestorePurchases.isEnabled = false

        if(SKPaymentQueue.canMakePayments()) {
            print("IAP is enabled, loading")
            let productID: NSSet = NSSet(objects: "com.IAPTesters.10Dolla", "com.IAPTesters.RemoveAds")
            self.productsRequest = SKProductsRequest(productIdentifiers: productID as! Set<String>)
            request?.delegate = self
            request?.start()
        } else {
            print("please enable IAPS")
        }
    }

func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        print("product request")
        let myProduct = response.products
        for product in myProduct {
            print("product added")
            print(product.productIdentifier)
            print(product.localizedTitle)
            print(product.localizedDescription)
            print(product.price)

            list.append(product)
        }

        outRemoveAds.isEnabled = true
        outAddCoins.isEnabled = true
        outRestorePurchases.isEnabled = true

        self.productsRequest = nil
    }

仅供参考,您对paymentQueueRestoreCompletedTransactionsFinished的实施不正确;您应该通过updatedTransactions事务状态处理.restored中已恢复的事务。 paymentQueueRestoreCompletedTransactionsFinished方法仅应用于更新UI或执行还原过程完成时所需的任何其他任务。

答案 1 :(得分:0)

如果我理解正确,那么您的实施问题就是您在iTunes中使用错误的标识符创建了您的产品。据我所知,产品标识符应该类似于您的应用程序包标识符,后跟您的产品功能i.e, COM.COMPANYNAME.MYNEWAPPLICATION.REMOVEADS, COM.COMPANYNAME.MYNEWAPPLICATION.10DOLLA

示例代码如,

typealias SSIAPHelperCompletion = (_ result: [SKProduct]?, _ error: Error?) ->Void

class SSIAPHelper: NSObject {
    fileprivate let productsRequest = SKProductsRequest(productIdentifiers: Set(arrayLiteral: "com.companyname.appname.removeads","com.companyname.appname.10dolla"))

    fileprivate var completion: SSIAPHelperCompletion?

    static let shared = SSIAPHelper()

    func requestProducts(completionHandler: @escaping SSIAPHelperCompletion) {
        self.completion = completionHandler
        self.productsRequest.delegate = SSIAPHelper.shared
        self.productsRequest.start()
    }
}

extension SSIAPHelper: SKProductsRequestDelegate{
    func requestDidFinish(_ request: SKRequest) {
        print(#function)
    }

    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        print(#function, response.products)
        if let lCompletion = self.completion{
            lCompletion(response.products, nil)
        }
    }

    func request(_ request: SKRequest, didFailWithError error: Error) {
        print(#function)
    }
}

您只需在viewDidLoad()

中调用以下功能即可获得产品
SSIAPHelper.shared.requestProducts(completionHandler: { (result, error) in

            })

答案 2 :(得分:0)

事实证明我的银行和税务信息填写不正确。我补充了它,而且我不得不等待大约30分钟再次工作。现在一切正常!感谢所有帮助