介绍
对于所有希望获得更多收入并通过其应用程序提供额外内容和功能的开发人员来说,应用程序内购买是一项很棒的功能。 例如,对于游戏,您可以购买宝石或硬币,对于摄影应用程序,则可以解锁新的效果或工具。 您可以使用信用卡或其他付款方式完成所有这些操作,而无需退出应用程序。
在本教程中,我将介绍在iTunes Connect上创建可消耗和不可消耗 IAP产品的所有必要步骤,并向您显示购买这两种产品所需的代码。 我已经制作了一个带有标签和两个按钮的示例Xcode项目 ,因此请下载它,并按照本教程进行操作以了解其工作原理。
在iTunes Connect中创建沙盒测试器
我假设您已经在iTunes Connect的“ 我的应用程序”部分中创建了iOS应用程序。 您应该做的第一件事是创建一个沙箱测试器以在您的真实设备上测试IAP(没有模拟器,它不支持应用内购买)。
输入用户和角色 ,转到“ 沙箱测试器”选项卡,然后单击“ 测试器”旁边的( + )符号。
填写表格以添加新的沙箱测试器。 保存信息后,返回“ 我的应用程序”部分,然后单击应用程序的图标以输入其详细信息并创建IAP产品。
在iTunes Connect中创建IAP产品
消费品
点击功能标签,然后点击应用内购买旁边的( + )符号。 您一次可以创建一个产品,因此让我们从一个消耗品开始。
顾名思义, 耗材 IAP是一种可以多次购买的产品。 我们将使用它在演示应用程序中收集其他“硬币”。
单击创建以初始化您的IAP项目。 在下一个屏幕上,您可以设置有关产品的所有信息:
- 参考名称 :此名称将在iTunes Connect和“ 销售和趋势”报告中使用。 它不会显示在App Store上,您可以输入所需的任何名称,但不能超过64个字符。
- 产品ID :应用程序会提取该ID以识别您的产品的唯一字母数字标识符。 通常,开发人员将Web反向语法用于产品ID。 在此示例中,我们选择com.iaptutorial.coins 。 稍后,我们将此ID作为字符串粘贴到我们的代码中。
- 价格 :从下拉菜单中选择价格等级。 请记住,要在App Store上出售您的应用内购买产品,您必须已在“ 协议,税收和银行业务”部分中申请了“付费应用协议 ” 。
- 本地化 :在本教程中,我们仅选择了英语,但是您可以通过单击( + )按钮添加更多语言。 然后键入显示名称和描述 。 两者都将在App Store上可见。
- 屏幕截图 :上传屏幕截图以供查看。 它不会显示在App Store中,并且必须具有适用于您的应用平台的有效尺寸,因此,如果您的应用是通用应用,则可以上传iPad屏幕截图。
- 审核说明 :有关您的IAP的任何其他信息,可能会对审核者有所帮助。
完成后,单击“ 保存” ,您将收到以下警报:
您的首次应用内购买必须与新的应用版本一起提交。 从应用程序的“应用程序内购买”部分中选择它,然后单击“提交”。
非消耗品
现在,单击“ 游戏中心”按钮左上方,右上方列表中的“应用内购买”按钮,然后添加新的IAP产品。 这次,选择“ 非消耗品”选项:
点击创建,然后重复我们上面提到的步骤。 由于这将是非消耗性产品,因此用户只能购买一次,并且Apple需要能够恢复此类购买。 如果您卸载该应用程序并再次重新安装,或者从具有相同Apple ID的另一台设备下载该应用程序,并且需要取回您的购买而无需支付两次费用,则会发生这种情况。 因此,稍后我们将在代码中添加“还原购买”功能。
我们现在创建的产品ID为com.iaptutorial.premium ,价格层为2.99美元。 我们称之为解锁高级版。
填写完所有字段后,保存产品并返回“应用内购买”页面。 现在,您应该拥有两个产品的列表,其名称 , 类型 , ID和状态设置为“ 准备提交” 。
通过单击“ App Store”和“ 准备提交”按钮返回到您的应用程序页面。 向下滚动到“ 常规应用信息”下方的“应用内购买”部分,然后单击(+)按钮添加您的IAP产品。
选择所有它们,然后单击“完成” 。
最后,单击屏幕右上角的“ 保存” ,即可在iTunes Connect上配置应用内购买产品。
在iOS设备上登录沙盒测试器
在阅读代码之前,还有另外一件事要做。 在您的iOS设备上转到“设置” >“ iTunes&App Store ”。 如果您已经使用原始Apple ID登录,请点击它并选择注销 。 然后,只需使用您创建的沙箱测试器的凭据登录即可。 登录后,您可能会收到如下警报:
只需忽略其消息,然后点击取消 。 您的设备在尝试进行购买时会再次询问您的沙箱登录凭据,并且会识别您的测试帐户,因此您进行任何购买时都不会从信用卡中收取一分钱。
退出设置 ,通过USB电缆将设备插入Mac,最后开始编码!
代码
如果您下载了我们的演示项目,您将看到已编写了应用内购买的所有必需代码,因此,如果运行它,您将获得以下内容:
如果要测试应用程序,则应将捆绑包标识符更改为自己的ID。 否则,Xcode将不允许您在真实设备上运行该应用程序,并且该应用程序将无法识别您创建的两个IAP产品。
输入ViewController.swift并检查代码。 首先,我们添加了StoreKit
的import语句和我们需要的委托以跟踪付款交易和产品请求。
import StoreKit
class ViewController: UIViewController,
SKProductsRequestDelegate,
SKPaymentTransactionObserver
{
然后,我们声明了一些有用的视图。
/* Views */
@IBOutlet weak var coinsLabel: UILabel!
@IBOutlet weak var premiumLabel: UILabel!
@IBOutlet weak var consumableLabel: UILabel!
@IBOutlet weak var nonConsumableLabel: UILabel!
coinsLabel
和premiumLabel
将用于显示两种产品的购买结果。 consumableLabel
和nonConsumableLabel
会显示每个IAP产品,我们以前在iTunes Connect创建者的描述和价格。
现在是时候添加一些变量了:
/* Variables */
let COINS_PRODUCT_ID = "com.iaptutorial.coins"
let PREMIUM_PRODUCT_ID = "com.iaptutorial.premium"
var productID = ""
var productsRequest = SKProductsRequest()
var iapProducts = [SKProduct]()
var nonConsumablePurchaseMade = UserDefaults.standard.bool(forKey: "nonConsumablePurchaseMade")
var coins = UserDefaults.standard.integer(forKey: "coins")
前两行是回忆我们的产品ID。 这些字符串必须与iTunes Connect的“应用内购买”部分中注册的字符串完全匹配,这一点很重要。
-
productID
是一个字符串,稍后我们将使用它来检测我们将选择购买的产品。 -
productsRequest
是SKProductsRequest
一个实例,需要从iTC上的应用程序中搜索IAP产品。 -
iapProducts
是一个简单的数组SKProducts
。 请注意,SK前缀表示StoreKit,这是我们将用于处理购买的iOS框架。
最后两行加载了两个Boolean
类型和Integer
类型的变量,分别用于跟踪硬币和高级版本的购买,这两个变量分别是消耗品和非消耗品。
该应用程序启动后, viewDidLoad()
的以下代码将执行一些操作:
// Check your In-App Purchases
print("NON CONSUMABLE PURCHASE MADE: \(nonConsumablePurchaseMade)")
print("COINS: \(coins)")
// Set text
coinsLabel.text = "COINS: \(coins)"
if nonConsumablePurchaseMade { premiumLabel.text = "Premium version PURCHASED!"
} else { premiumLabel.text = "Premium version LOCKED!"}
// Fetch IAP Products available
fetchAvailableProducts()
首先,我们只将每次购买记录到Xcode控制台。 然后,我们显示使用coinsLabel
购买的硬币coinsLabel
。 由于我们是第一次运行演示应用程序,它将显示COINS:0 。
if
语句根据是否购买了非消耗性产品来设置premiumLabel
的文本。 首先,它将显示Premium版本已锁定! 由于我们尚未进行溢价购买。
代码的最后一行调用了一个我们稍后将看到的方法,该方法只是获取我们先前存储在iTC中的产品。
现在,让我们看看我们在演示应用程序中设置的两个购买按钮的作用:
// MARK: - BUY 10 COINS BUTTON
@IBAction func buy10coinsButt(_ sender: Any) {
purchaseMyProduct(product: iapProducts[0])
}
// MARK: - UNLOCK PREMIUM BUTTON
@IBAction func unlockPremiumButt(_ sender: Any) {
purchaseMyProduct(product: iapProducts[1])
}
这两种方法都将调用一个函数,该函数将检查设备是否可以进行购买,如果可以,则该应用程序将调用StoreKit委托方法来处理购买。
如前所述,我们需要第三个按钮来还原我们的非消耗品购买。 这是它的代码:
// MARK: - RESTORE NON-CONSUMABLE PURCHASE BUTTON
@IBAction func restorePurchaseButt(_ sender: Any) {
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().restoreCompletedTransactions()
}
func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
nonConsumablePurchaseMade = true
UserDefaults.standard.set(nonConsumablePurchaseMade, forKey: "nonConsumablePurchaseMade")
UIAlertView(title: "IAP Tutorial",
message: "You've successfully restored your purchase!",
delegate: nil, cancelButtonTitle: "OK").show()
}
IBAction
功能已附加到情节提要中的“恢复购买”按钮上,并开始连接到Apple的应用内购买系统以恢复购买(如果已完成)。
paymentQueueRestoreCompletedTransactionsFinished()
是StoreKit框架的委托方法,在成功恢复购买后,该方法会将nonConsumablePurchaseMade
变量保存为true。
我们已经完成了按钮,所以让我们看看fetchAvailableProducts()
函数的作用:
// MARK: - FETCH AVAILABLE IAP PRODUCTS
func fetchAvailableProducts() {
// Put here your IAP Products ID's
let productIdentifiers = NSSet(objects:
COINS_PRODUCT_ID,
PREMIUM_PRODUCT_ID
)
productsRequest = SKProductsRequest(productIdentifiers: productIdentifiers as! Set<String>)
productsRequest.delegate = self
productsRequest.start()
}
我们首先创建一个NSSet
实例,它基本上是一个字符串数组。 我们将在此存储先前声明的两个产品ID。
然后,我们基于这些标识符启动一个SKProductsRequest
,以使该应用显示有关IAP产品的信息(描述和价格),该信息将通过此委托方法进行处理:
// MARK: - REQUEST IAP PRODUCTS
func productsRequest (_ request:SKProductsRequest, didReceive response:SKProductsResponse) {
if (response.products.count > 0) {
iapProducts = response.products
// 1st IAP Product (Consumable) ------------------------------------
let firstProduct = response.products[0] as SKProduct
// Get its price from iTunes Connect
let numberFormatter = NumberFormatter()
numberFormatter.formatterBehavior = .behavior10_4
numberFormatter.numberStyle = .currency
numberFormatter.locale = firstProduct.priceLocale
let price1Str = numberFormatter.string(from: firstProduct.price)
// Show its description
consumableLabel.text = firstProduct.localizedDescription + "\nfor just \(price1Str!)"
// ------------------------------------------------
// 2nd IAP Product (Non-Consumable) ------------------------------
let secondProd = response.products[1] as SKProduct
// Get its price from iTunes Connect
numberFormatter.locale = secondProd.priceLocale
let price2Str = numberFormatter.string(from: secondProd.price)
// Show its description
nonConsumableLabel.text = secondProd.localizedDescription + "\nfor just \(price2Str!)"
// ------------------------------------
}
}
在上面的功能中,我们首先必须检查iTunes Connect中是否注册了任何产品,并相应地设置我们的iapProducts
数组。 然后,我们可以初始化两个SKProducts并将其描述和价格打印在标签上。
在进入应用内购买代码的核心之前,我们需要更多的功能:
// MARK: - MAKE PURCHASE OF A PRODUCT
func canMakePurchases() -> Bool { return SKPaymentQueue.canMakePayments() }
func purchaseMyProduct(product: SKProduct) {
if self.canMakePurchases() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(self)
SKPaymentQueue.default().add(payment)
print("PRODUCT TO PURCHASE: \(product.productIdentifier)")
productID = product.productIdentifier
// IAP Purchases dsabled on the Device
} else {
UIAlertView(title: "IAP Tutorial",
message: "Purchases are disabled in your device!",
delegate: nil, cancelButtonTitle: "OK").show()
}
}
第一个检查我们的设备是否能够购物。 第二个功能是我们从两个按钮调用的功能。 它启动付款队列,并将我们的productID
变量更改为选定的productIdentifier
。
现在,我们终于到达了最后一个委托方法,该方法处理付款结果:
// MARK:- IAP PAYMENT QUEUE
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction:AnyObject in transactions {
if let trans = transaction as? SKPaymentTransaction {
switch trans.transactionState {
case .purchased:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
// The Consumable product (10 coins) has been purchased -> gain 10 extra coins!
if productID == COINS_PRODUCT_ID {
// Add 10 coins and save their total amount
coins += 10
UserDefaults.standard.set(coins, forKey: "coins")
coinsLabel.text = "COINS: \(coins)"
UIAlertView(title: "IAP Tutorial",
message: "You've successfully bought 10 extra coins!",
delegate: nil,
cancelButtonTitle: "OK").show()
// The Non-Consumable product (Premium) has been purchased!
} else if productID == PREMIUM_PRODUCT_ID {
// Save your purchase locally (needed only for Non-Consumable IAP)
nonConsumablePurchaseMade = true
UserDefaults.standard.set(nonConsumablePurchaseMade, forKey: "nonConsumablePurchaseMade")
premiumLabel.text = "Premium version PURCHASED!"
UIAlertView(title: "IAP Tutorial",
message: "You've successfully unlocked the Premium version!",
delegate: nil,
cancelButtonTitle: "OK").show()
}
break
case .failed:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break
case .restored:
SKPaymentQueue.default().finishTransaction(transaction as! SKPaymentTransaction)
break
default: break
}}}
}
此功能具有一个switch
语句,用于检查付款的每种状态。 如果成功完成购买并完成交易,则调用第一种case
。
在此区块内,我们必须检查我们选择了哪个产品ID,并执行必要的操作来更新我们的应用程序-因此,如果我们用户购买了10个额外的硬币,我们将向coins
变量中添加10个,并使用UserDefaults
保存其值,显示我们获得的新硬币数量,并发出警报。
请注意,由于它是消耗性的IAP,因此您可以无限制地进行多次购买,并且不需要恢复购买功能。
同样,如果我们购买了非消耗性优质产品,则该应用会将我们的nonConsumablePurchaseMade
变量设置为true
,保存该变量,更改premiumLabel
的文本,并发出警报以通知您购买已成功。
其他两种cases
处理失败和恢复的付款结果。 如果您的交易由于某种原因失败或您恢复了非消耗品的购买,则该应用将自行触发自定义提醒。
而已! 现在,只需确保您已使用Sandbox Tester凭据登录并运行该应用程序即可对其进行测试。 第一次,您会收到这样的警报:
选择“ 使用现有的Apple ID” ,然后再次输入您的Sandbox Tester的用户名和密码进行登录。这是因为该应用只能从iTunes&App Store设置中识别真实用户,而不能识别沙盒用户。
登录后,就可以购买两种产品。
CodeCanyon模板
如果您使用iOS,并且想深入了解Swift语言和应用程序开发,请在CodeCanyon上查看一些我的iOS应用程序模板 。
Envato市场上还有数百种其他iOS应用程序模板 ,可以重新设置外观并确保加快工作流程。 去看看他们! 您可能只是在下一个应用程序上节省了工作时间。
结论
在本教程中,我们介绍了在iTunes Connect上创建应用内购买产品所需的所有步骤,以及如何编写代码以在您的应用中启用它们。 我希望您能够在下一个iOS应用中使用这些知识!
翻译自: https://code.tutsplus.com/tutorials/in-app-purchase-tutorial-with-swift-3-ios-sdk--cms-27595