应用内购买无法正常工作,显示无产品。

10

我正在学习苹果提供的应用内购买。所以我按照这个教程进行操作: http://www.appcoda.com/in-app-purchase-tutorial/

我按照这个教程中的所有步骤进行了操作。首先,我创建了一个应用程序ID,然后使用该应用程序ID在iTunes中创建一个应用程序。然后我创建了两个产品ID为“com.outlines.feature1”和“com.outlines.feature2”的应用内购买,它们都是可消耗品。其余的代码我只需按照上述教程的步骤进行操作。

import UIKit
import StoreKit

protocol IAPurchaceViewControllerDelegate {
    func didBuyColorsCollection(collectionIndex: Int)
}


class IAPurchaceViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, SKProductsRequestDelegate, SKPaymentTransactionObserver {

@IBOutlet weak var tblProducts: UITableView!

var delegate: IAPurchaceViewControllerDelegate!

var selectedProductIndex: Int!
var transactionInProgress = false

let productIdentifiers = NSSet(array: ["com.outlines.feature1", "com.outlines.feature2"])
 var product: SKProduct?
var productsArray = Array<SKProduct>()

override func viewDidLoad() {
    super.viewDidLoad()

    // Do any additional setup after loading the view.
    tblProducts.delegate = self
    tblProducts.dataSource = self

    //checks whether the In-App feature is activated or not
    requestProductInfo()

    SKPaymentQueue.defaultQueue().addTransactionObserver(self)
}

func requestProductInfo(){
    if SKPaymentQueue.canMakePayments() {
        let request = SKProductsRequest(productIdentifiers:
            productIdentifiers as! Set<String>)
        print("This is the request to be sent \(request)")
        request.delegate = self
        request.start()//calls productsRequest() function
    }
    else {
        print("Cannot perform In App Purchases.")
    }
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

// MARK: IBAction method implementation

@IBAction func dismiss(sender: AnyObject) {
    dismissViewControllerAnimated(true, completion: nil)
}


// MARK: UITableView method implementation

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    return 1
}


func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return productsArray.count
}


func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("idCellProduct", forIndexPath: indexPath) as UITableViewCell

    let product = productsArray[indexPath.row]
    cell.textLabel?.text = product.localizedTitle
    cell.detailTextLabel?.text = product.localizedDescription

    return cell
}


func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    selectedProductIndex = indexPath.row
    showActions()
    tableView.cellForRowAtIndexPath(indexPath)?.selected = false
}

func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    return 80.0
}




/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) {
    if response.products.count != 0 {
        for product in response.products {
            productsArray.append(product as SKProduct)
        }

        tblProducts.reloadData()
    }
    else {
        print("There are no products.")
    }

    if response.invalidProductIdentifiers.count != 0 {
        print("Invalid "+response.invalidProductIdentifiers.description)
    }
}

func showActions() {
    if transactionInProgress {
        return
    }

    let actionSheetController = UIAlertController(title: "IAPDemo", message: "What do you want to do?", preferredStyle: UIAlertControllerStyle.ActionSheet)

    let buyAction = UIAlertAction(title: "Buy", style: UIAlertActionStyle.Default) { (action) -> Void in
        let payment = SKPayment(product: self.productsArray[self.selectedProductIndex] as SKProduct)
        SKPaymentQueue.defaultQueue().addPayment(payment)
        self.transactionInProgress = true
    }

    let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) { (action) -> Void in

    }

    actionSheetController.addAction(buyAction)
    actionSheetController.addAction(cancelAction)

    presentViewController(actionSheetController, animated: true, completion: nil)
}

func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
    for transaction in transactions as [SKPaymentTransaction] {
        switch transaction.transactionState {
        case SKPaymentTransactionState.Purchased:
            print("Transaction completed successfully.")
            SKPaymentQueue.defaultQueue().finishTransaction(transaction)
            transactionInProgress = false
            delegate.didBuyColorsCollection(selectedProductIndex)

        case SKPaymentTransactionState.Failed:
            print("Transaction Failed");
            SKPaymentQueue.defaultQueue().finishTransaction(transaction)
            transactionInProgress = false

        default:
            print(transaction.transactionState.rawValue)
        }
    }
}  
}

没有错误,但是在iPhone上运行时,控制台会显示:

This is the request to be sent <SKProductsRequest: 0x15d86210>
There are no products.
Invalid ["com.outlines.feature1", "com.outlines.feature2"]

控制台没有显示任何产品,但是我已经在我的iTunes id中添加了两个应用内购买功能。这里是截图:在iTunes中的应用内购买

有人能告诉我我在做什么错了吗?


1
请在显示InApp购买的屏幕上截图。如果状态更改为“准备提交”,则它将起作用。最好遵循“InApp教程”。(https://www.raywenderlich.com/122144/in-app-purchase-tutorial) - TheTiger
@krazzie KAy,我也遇到了同样的问题,尽管我已经完成了许可协议过程。你能帮我解决这个问题吗? - vijju
5个回答

51

我最终解决了这个问题。代码和应用内购买制作过程中没有错误。之前提到的上传快照的解决方案也不是问题所在。

问题出在协议、税收和银行合同上。教程中没有提到,我们需要在iTunes的协议、税收和银行页面完成一个合同,而我没有这样做。填写完合同表格后,它将被处理。然后合同即可生效,此时在iTunes创建的应用内购买项目就会被识别。


2
我有同样的问题。我填写了所有的银行和税务信息,但仍然没有产品可用。我设置了所有必需的信息,大约4-5个小时前,但仍然没有任何变化。需要更多时间吗? - rootpanthera
抱歉回复晚了,但是如果我没记错的话,确实需要2-4天的时间。 - Krazzie KAy
我在完成在iTunes Connect添加我的信息后,大约5-10分钟后它对我起作用了。 - Mason Ballowe
协议、税收和银行在哪里?我在用户账户中没有找到。需要管理员账户吗? - Rajamohan S
1
哦,我也是通过困难的方式发现了这个问题。真不敢相信这个问题没有被记录在任何地方,而且还需要用于测试!为什么他们要求测试时使用它呢? - Blue Bot

18

在您的设备上测试IAP时,不需要提交截图。只有在提交应用程序时才需要截图。

请确保您对以下每个问题都能回答“是”:

  1. 已为您的App ID启用了应用内购买吗?
  2. 已经为您的产品勾选了“可出售”吗?
  3. 您的项目的.plist Bundle ID是否与您的App ID匹配?
  4. 已经为新的App ID生成并安装了新的配置文件吗?
  5. 已将您的项目配置为使用此新的配置文件进行代码签名吗?
  6. 在进行SKProductRequest请求时,是否使用了完整的产品ID?
  7. 自从将产品添加到iTunes Connect以来,您等待了几个小时?
  8. 您尝试删除设备上的应用程序并重新安装了吗?
  9. 您的设备越狱了吗?如果是,您需要恢复越狱才能使IAP正常工作。

如果您对这些问题中的任何一个回答“否”,那么这就是您的问题所在。

如果您正在使用tableView,请确保还设置了正确的参数以在单元格中加载。可能您的问题与tableView相关的连接有关。


1
在所有这些选项中,我必须拒绝最后两个选项。然而,我下载了教程项目并在模拟器中运行它,看起来显示了IAP产品,只是在模拟器中购买功能无法正常工作。但在我的情况下,IAP产品无效,我不明白为什么,因为我已经按照教程中的确切步骤进行了操作。 - Krazzie KAy
你使用了下载的同一个项目吗?还是创建了新的项目? - Done
我从那个教程下载了起始项目,并对其进行了修改。 - Krazzie KAy
这是个问题。当我在做教程时,我会创建新项目并复制类... - Done
在完成以上步骤后,请确保在真实的Apple TV上进行测试(通过USB连接),而不是在模拟器上进行测试!这就是我无法获取有效产品ID的问题所在。 - Ricardo Barroso
我也发现,在完成所有其他工作之后,递增应用程序版本号会有所帮助。 - Andrew Smith

1
你需要在productID字段中使用完整的字符串com.product.productID。界面让你相信你只需要最后一部分:productID,但是直到我重新创建了带有完整显式ID的新应用内购买,它才起作用:(可能与前一天接受税收/银行业务有关。

0

您的应用内购买尚未完全设置,如您所见,它们的状态为“等待截图”:

在提交应用内购买审核之前,您必须上传一张截图。此截图仅用于审核目的,不会显示在App Store上。截图大小必须至少为312x390像素,分辨率至少为72 DPI。

通常我会使用应用内购买建议的提示进行截图,然后将其裁剪并上传到iTunesConnect。

完成以上步骤后,您当前的购买应该已经具备了“准备提交”的状态:

enter image description here

顺便说一句,应用新更改需要一些时间才能生效,请耐心等待:)


无所谓,编辑您的购买记录,您会看到底部有一个屏幕应上传到的部分。 - Alex Kosyakov
好的,我会尝试。我应该使用任意图片吗? - Krazzie KAy
它不起作用。我刚刚上传了一张截图,应用内购买显示“准备提交”,我刚刚运行了我的项目,仍然显示相同的错误!! - Krazzie KAy
请阅读完整答案。 - Alex Kosyakov
让我们在聊天中继续这个讨论 - Krazzie KAy
显示剩余3条评论

0

被接受的答案是正确的。

但我想指出,在我的情况下,原因是我最近更新了我的苹果开发者会员资格,并且在更新后,我没有更新合同。

同意并重新提交合同后,我的产品 SKU 开始像以前一样显示。

显然,付费应用程序合同必须由您和苹果签署。这可以防止 SKProductsRequest 验证标识符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接