如何将应用程序内购买添加到iOS应用程序?

如何将应用程序内购买添加到iOS应用程序? 什么是所有的细节,是否有任何示例代码?

这意味着如何将应用内购买添加到iOS应用中

在Xcode 5+中获得适用于iOS 10 (和iOS 9, 8 and 7 9,8 iOS 9, 8 and 7 )的应用程序内购买的最佳方法是执行以下操作:

  1. 转到itunes.connect.apple.com并login
  2. 点击My Apps然后点击您想添加购买的应用程序
  3. 点击Features标题,然后select左侧In-App Purchases
  4. 点击中间的+图标
  5. 对于本教程,我们将添加应用内购买以删除广告,因此请selectnon-consumable 。 如果您打算向用户发送一件物品,或给他们购买一次以上的物品,您可以selectconsumable
  6. 对于参考名称,把任何你想要的(但要确保你知道它是什么)
  7. 对于产品ID放tld.websitename.appname.referencename这将工作最好的,所以例如,你可以使用com.jojodmo.blix.removeads
  8. selectcleared for sale ,然后select价格层为1(99¢)。 第2级将是1.99美元,第3级将是2.99美元。 如果您点击view pricing matrix我们build议您使用第1级,因为这通常是任何人为了移除广告所付出的代价。
  9. 点击蓝色的add languagebutton,并input信息。 这将全部显示给客户,所以不要把任何你不希望他们看到的东西
  10. hosting content with Appleselect
  11. 您可以将评论注释留空。
  12. 跳过screenshot for review 现在 ,我们跳过的一切,我们将回来。
  13. 点击“保存”

您的产品ID可能需要几个小时才能在iTunesConnect注册,因此请耐心等待。

现在您已经在iTunesConnect上设置了应用程序内购买信息,进入您的Xcode项目,然后进入应用程序pipe理器(您的方法和头文件位于顶部的类似蓝页的图标),然后单击您的应用程序根据目标(应该是第一个),然后去一般。 在底部,你应该看到linked frameworks and libraries单击小加号,并添加框架StoreKit.framework如果你不这样做,应用程序内购买将无法正常工作!

如果您使用Objective-C作为您的应用程序的语言,则可以跳过这五个步骤。 否则,如果您正在使用Swift,请执行以下操作:

  1. 通过转到File > New > File...Command⌘ + N )创build一个新的.h (标题)文件。 这个文件在本教程的其余部分将被称为“你的.h文件”

  2. 出现提示时,单击“ 创build桥接头” 。 这将是我们的桥接头文件。 如果没有提示,请转到步骤3.如果提示,跳过步骤3并直接转到步骤4。

  3. 在主项目文件夹中创build另一个名为Bridge.h .h文件,然后转到应用程序pipe理器(蓝色页面图标),然后在“ Targets部分select您的应用程序,然后单击“ Build Settings 。 findSwift编译器的代码生成选项,然后将Objective-C桥接头选项设置为Bridge.h

  4. 在桥接头文件中,添加#import "MyObjectiveCHeaderFile.h" ,其中MyObjectiveCHeaderFile是在第一步中创build的头文件的名称。 所以,例如,如果你命名了你的头文件InAppPurchase.h ,你可以在你的头文件中join#import "InAppPurchase.h"这一行。

  5. 通过转到File > New > File...Command⌘ + N )创build一个新的Objective-C Methods( .m )文件。 将其命名为与步骤1中创build的头文件相同。例如,如果您在第1步InAppPurchase.h中调用该文件,则会调用此新文件InAppPurchase.m 。 这个文件在本教程的其余部分将被称为“您的.m文件”。

现在我们要进入实际的编码。 将下面的代码添加到.h文件中:

 BOOL areAdsRemoved; - (IBAction)restore; - (IBAction)tapsRemoveAds; 

接下来,您需要将StoreKit框架导入到.m文件中,并在您的@interface声明后添加SKProductsRequestDelegateSKPaymentTransactionObserver

 #import <StoreKit/StoreKit.h> //put the name of your view controller in place of MyViewController @interface MyViewController() <SKProductsRequestDelegate, SKPaymentTransactionObserver> @end @implementation MyViewController //the name of your view controller (same as above) //the code below will be added here @end 

现在将以下内容添加到.m文件中,这部分变得复杂了,所以我build议您阅读代码中的注释:

 //If you have more than one in-app purchase, you can define both of //of them here. So, for example, you could define both kRemoveAdsProductIdentifier //and kBuyCurrencyProductIdentifier with their respective product ids // //for this example, we will only use one product #define kRemoveAdsProductIdentifier @"put your product id (the one that we just made in iTunesConnect) in here" - (IBAction)tapsRemoveAds{ NSLog(@"User requests to remove ads"); if([SKPaymentQueue canMakePayments]){ NSLog(@"User can make payments"); //If you have more than one in-app purchase, and would like //to have the user purchase a different product, simply define //another function and replace kRemoveAdsProductIdentifier with //the identifier for the other product SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kRemoveAdsProductIdentifier]]; productsRequest.delegate = self; [productsRequest start]; } else{ NSLog(@"User cannot make payments due to parental controls"); //this is called the user cannot make payments, most likely due to parental controls } } - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{ SKProduct *validProduct = nil; int count = [response.products count]; if(count > 0){ validProduct = [response.products objectAtIndex:0]; NSLog(@"Products Available!"); [self purchase:validProduct]; } else if(!validProduct){ NSLog(@"No products available"); //this is called if your product id is not valid, this shouldn't be called unless that happens. } } - (void)purchase:(SKProduct *)product{ SKPayment *payment = [SKPayment paymentWithProduct:product]; [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; [[SKPaymentQueue defaultQueue] addPayment:payment]; } - (IBAction) restore{ //this is called when the user restores purchases, you should hook this up to a button [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; } - (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue { NSLog(@"received restored transactions: %i", queue.transactions.count); for(SKPaymentTransaction *transaction in queue.transactions){ if(transaction.transactionState == SKPaymentTransactionStateRestored){ //called when the user successfully restores a purchase NSLog(@"Transaction state -> Restored"); //if you have more than one in-app purchase product, //you restore the correct product for the identifier. //For example, you could use //if(productID == kRemoveAdsProductIdentifier) //to get the product identifier for the //restored purchases, you can use // //NSString *productID = transaction.payment.productIdentifier; [self doRemoveAds]; [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; break; } } } - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{ for(SKPaymentTransaction *transaction in transactions){ //if you have multiple in app purchases in your app, //you can get the product identifier of this transaction //by using transaction.payment.productIdentifier // //then, check the identifier against the product IDs //that you have defined to check which product the user //just purchased switch(transaction.transactionState){ case SKPaymentTransactionStatePurchasing: NSLog(@"Transaction state -> Purchasing"); //called when the user is in the process of purchasing, do not add any of your own code here. break; case SKPaymentTransactionStatePurchased: //this is called when the user has successfully purchased the package (Cha-Ching!) [self doRemoveAds]; //you can add your code for what you want to happen when the user buys the purchase here, for this tutorial we use removing ads [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; NSLog(@"Transaction state -> Purchased"); break; case SKPaymentTransactionStateRestored: NSLog(@"Transaction state -> Restored"); //add the same code as you did from SKPaymentTransactionStatePurchased here [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; break; case SKPaymentTransactionStateFailed: //called when the transaction does not finish if(transaction.error.code == SKErrorPaymentCancelled){ NSLog(@"Transaction state -> Cancelled"); //the user cancelled the payment ;( } [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; break; } } } 

现在,您要添加代码,以确定用户完成交易后会发生什么情况,对于本教程,我们使用删除添加,您将不得不添加自己的代码,以查看加载横幅视图时发生的情况。

 - (void)doRemoveAds{ ADBannerView *banner; [banner setAlpha:0]; areAdsRemoved = YES; removeAdsButton.hidden = YES; removeAdsButton.enabled = NO; [[NSUserDefaults standardUserDefaults] setBool:areAdsRemoved forKey:@"areAdsRemoved"]; //use NSUserDefaults so that you can load whether or not they bought it //it would be better to use KeyChain access, or something more secure //to store the user data, because NSUserDefaults can be changed. //You're average downloader won't be able to change it very easily, but //it's still best to use something more secure than NSUserDefaults. //For the purpose of this tutorial, though, we're going to use NSUserDefaults [[NSUserDefaults standardUserDefaults] synchronize]; } 

如果您的应用程序中没有广告,则可以使用任何您想要的其他内容。 例如,我们可以使背景的颜色为蓝色。 要做到这一点,我们希望使用:

 - (void)doRemoveAds{ [self.view setBackgroundColor:[UIColor blueColor]]; areAdsRemoved = YES //set the bool for whether or not they purchased it to YES, you could use your own boolean here, but you would have to declare it in your .h file [[NSUserDefaults standardUserDefaults] setBool:areAdsRemoved forKey:@"areAdsRemoved"]; //use NSUserDefaults so that you can load wether or not they bought it [[NSUserDefaults standardUserDefaults] synchronize]; } 

现在,在你的viewDidLoad方法的某个地方,你将要添加下面的代码:

 areAdsRemoved = [[NSUserDefaults standardUserDefaults] boolForKey:@"areAdsRemoved"]; [[NSUserDefaults standardUserDefaults] synchronize]; //this will load wether or not they bought the in-app purchase if(areAdsRemoved){ [self.view setBackgroundColor:[UIColor blueColor]]; //if they did buy it, set the background to blue, if your using the code above to set the background to blue, if your removing ads, your going to have to make your own code here } 

现在,您已经添加了所有的代码,进入您的.xibstoryboard文件,并添加两个button,一个说购买,另一个说恢复。 将tapsRemoveAds IBAction到您刚购买的购买button,并将restore IBAction连接到还原button。 restore操作将检查用户以前是否购买了应用程序内购买,如果他们还没有购买,则可以免费提供应用程序内购买。

接下来,进入iTunesConnect ,然后单击Users and Roles然后单击Sandbox Testers标题,然后单击左侧的符号表示Testers 。 你可以随意放置姓名,电子邮件不必是真实的 – 你只需要记住它。 input一个密码(你将不得不记住)并填写其余的信息。 我build议您将Date of Birthdate设定为使用户18岁或以上的date。 App Store Territory必须位于正确的国家/地区。 接下来,注销您现有的iTunes帐户(您可以在本教程后重新login)。

现在,在你的iOS设备上运行你的应用程序,如果你尝试在模拟器上运行它,购买总是错误的,你必须在你的iOS设备上运行它。 一旦应用程序正在运行,点击购买button。 当系统提示您login到您的iTunes帐户时,请以我们刚刚创build的testing用户身份login。 接下来,当它要求您确认购买99¢或任何您设置的价格层时, 拿起一个屏幕快照,这是你将用于screenshot for review在iTunesConnect的screenshot for review 。 现在取消付款。

现在,转到iTunesConnect ,然后转到My Apps > the app you have the In-app purchase on > the app you have the In-app purchase on In-App Purchases 。 然后点击您的应用内购买,然后点击应用内购买详情下的修改。 完成之后,将刚刚拿到iPhone上的照片导入到计算机中,然后将其作为截图进行上传,然后在评论注释中input您的TEST USER电子邮件和密码。 这将有助于苹果在审查过程中。

完成此操作后,请返回iOS设备上的应用程序,仍然以testing用户帐户login,然后单击购买button。 这次确认付款不要担心,这不会为您的帐户收取任何费用,testing用户帐户可以免费获得所有应用程序内购买确认付款后,确保用户实际购买产品时发生的情况发生。 如果没有,那么doRemoveAds方法将会出错。 同样,我build议使用将背景更改为蓝色来testing应用内购买,但这不应该是您实际的应用内购买。 如果一切正常,你很好走! 只要确保在将应用程序内容上传到iTunesConnect时,就可以将它们包含在新的二进制文件中!


以下是一些常见错误:

logging: No Products Available

这可能意味着三件事情:

  • 您没有在代码中放置正确的应用内购买ID(对于上述代码中的标识符kRemoveAdsProductIdentifier
  • 您没有清除在iTunesConnect上销售的应用程序内购买
  • 您没有等待在iTunesConnect中注册应用内购买ID。 等待几个小时从创buildID,你的问题应该得到解决。
  • 您没有填写您的协议,税务和银行信息。

如果第一次不行,不要感到沮丧! 不要放弃! 我花了大约5个小时才得到这个工作,大约10个小时寻找正确的代码! 如果你使用上面的代码,它应该工作正常。 如果您有任何问题请随时发表评论。

我希望这有助于所有希望在iOS应用程序中添加应用内购买的人。 干杯!

只需将Jojodmo代码翻译成Swift即可:

 class InAppPurchaseManager: NSObject , SKProductsRequestDelegate, SKPaymentTransactionObserver{ //If you have more than one in-app purchase, you can define both of //of them here. So, for example, you could define both kRemoveAdsProductIdentifier //and kBuyCurrencyProductIdentifier with their respective product ids // //for this example, we will only use one product let kRemoveAdsProductIdentifier = "put your product id (the one that we just made in iTunesConnect) in here" @IBAction func tapsRemoveAds() { NSLog("User requests to remove ads") if SKPaymentQueue.canMakePayments() { NSLog("User can make payments") //If you have more than one in-app purchase, and would like //to have the user purchase a different product, simply define //another function and replace kRemoveAdsProductIdentifier with //the identifier for the other product let set : Set<String> = [kRemoveAdsProductIdentifier] let productsRequest = SKProductsRequest(productIdentifiers: set) productsRequest.delegate = self productsRequest.start() } else { NSLog("User cannot make payments due to parental controls") //this is called the user cannot make payments, most likely due to parental controls } } func purchase(product : SKProduct) { let payment = SKPayment(product: product) SKPaymentQueue.defaultQueue().addTransactionObserver(self) SKPaymentQueue.defaultQueue().addPayment(payment) } func restore() { //this is called when the user restores purchases, you should hook this up to a button SKPaymentQueue.defaultQueue().addTransactionObserver(self) SKPaymentQueue.defaultQueue().restoreCompletedTransactions() } func doRemoveAds() { //TODO: implement } ///////////////////////////////////////////////// //////////////// store delegate ///////////////// ///////////////////////////////////////////////// // MARK: - store delegate - func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse) { if let validProduct = response.products.first { NSLog("Products Available!") self.purchase(validProduct) } else { NSLog("No products available") //this is called if your product id is not valid, this shouldn't be called unless that happens. } } func paymentQueueRestoreCompletedTransactionsFinished(queue: SKPaymentQueue) { NSLog("received restored transactions: \(queue.transactions.count)") for transaction in queue.transactions { if transaction.transactionState == .Restored { //called when the user successfully restores a purchase NSLog("Transaction state -> Restored") //if you have more than one in-app purchase product, //you restore the correct product for the identifier. //For example, you could use //if(productID == kRemoveAdsProductIdentifier) //to get the product identifier for the //restored purchases, you can use // //NSString *productID = transaction.payment.productIdentifier; self.doRemoveAds() SKPaymentQueue.defaultQueue().finishTransaction(transaction) break; } } } func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction in transactions { switch transaction.transactionState { case .Purchasing: NSLog("Transaction state -> Purchasing") //called when the user is in the process of purchasing, do not add any of your own code here. case .Purchased: //this is called when the user has successfully purchased the package (Cha-Ching!) self.doRemoveAds() //you can add your code for what you want to happen when the user buys the purchase here, for this tutorial we use removing ads SKPaymentQueue.defaultQueue().finishTransaction(transaction) NSLog("Transaction state -> Purchased") case .Restored: NSLog("Transaction state -> Restored") //add the same code as you did from SKPaymentTransactionStatePurchased here SKPaymentQueue.defaultQueue().finishTransaction(transaction) case .Failed: //called when the transaction does not finish if transaction.error?.code == SKErrorPaymentCancelled { NSLog("Transaction state -> Cancelled") //the user cancelled the payment ;( } SKPaymentQueue.defaultQueue().finishTransaction(transaction) case .Deferred: // The transaction is in the queue, but its final status is pending external action. NSLog("Transaction state -> Deferred") } } } } 

RMStore是一款用于应用程序内购买的轻量级iOS库。 它包装了StoreKit API并为asynchronous请求提供了方便的块。 购买产品和调用单一方法一样简单。

对于高级用户,这个库还提供收据validation,内容下载和交易持久性。

我知道我已经很晚了,但是当我学习IAP模型的时候,我也有类似的经历。

应用程序内购买是由Storekit框架实现的iOS中最全面的工作stream程之一。 如果你耐心阅读, 整个文档都是非常清晰的,但是在技术性方面有些先进。

总结:

1 – 请求产品 – 使用SKProductRequest&SKProductRequestDelegate类来发出产品ID的请求,并从您自己的itunesconnect商店接收它们。

这些SKProducts应该用来填充你的商店用户界面,用户可以用它来购买特定的产品。

2 – 发出付款申请 – 使用SKPayment&SKPaymentQueue将付款添加到交易队列中。

3 – 监视状态更新的事务队列 – 使用SKPaymentTransactionObserver协议的updatedTransactions方法监视状态:

 SKPaymentTransactionStatePurchasing - don't do anything SKPaymentTransactionStatePurchased - unlock product, finish the transaction SKPaymentTransactionStateFailed - show error, finish the transaction SKPaymentTransactionStateRestored - unlock product, finish the transaction 

4 – 恢复buttonstream – 使用SKPaymentQueue的restoreCompletedTransactions来完成这一步 – 第3步将采取SKPaymentTransactionObserver的以下方法的其余部分:

 paymentQueueRestoreCompletedTransactionsFinished restoreCompletedTransactionsFailedWithError 

下面是一个一步一步的教程(由我自己试图理解的结果),解释它。 最后还提供了可以直接使用的代码示例。

这是我创造的另一个解释某些东西,只有文本可以更好地描述。