Corona中文站

强大、易学的跨平台(iOS/Android)开发框架。QQ群1:74390406(满) 群2:221929599

导航

五分钟学会Corona(二十一) - 应用内支付
这个特性允许你支持应用内支付。当前,只有Apple iTunes Store被支持。在未来也许其他商店会加入这个特性。

Apple iTunes Store 的应用内支付

应用内支付允许用户购买额外的内容。然而, Apple iTunes Store只管理交易信息!开发者不能使用 Apple App Store来分发内容。所以,要么你捆绑内容在你的app里,等到付费之后来解锁这个内容;要么你不得不开发一个你自己的系统来下载付费后你想分发的内容。为了支持可下载内容,你应该使用我们新的 Network/AsynchHTTP API。

为了让你的app可以在Apple iTunes Store正常工作,你必须遵守在Apple的规则,关于在供应门户上发生供应和在iTunesConnect上发生购买。这个是一个复杂的过程。网上有许多有用的教程;一些文章的末尾都列有不错的建议。简短来说,关键步骤如下:

• 确保你向Apple提交了你的税收和银行信息。应用内支付在这些没有写清楚并不会工作,并且你也不会得到任何错误信息告诉你是这个问题。

• 在供应门户上,创建一个新的唯一且完全合格的AppID(例如 com.anscamobile.NewExampleInAppPurchase)(不要使用通配符)

• 为你的AppID创建一个供应配置信息。

• 在iTunes Connect上,用相同的 bundle identifier创建一个新App

• 用他们的产品标识符和分类, 添加你的可购买项。(消费品,非消费品,或订阅)

• 添加然后配置一个测试用户帐号,来实验你的应用内支付代码


这里有个有用的范例工程: InAppDemo.zip

使用Corona的store模块

你也需要在你的Corona应用中创建代码,来处理App Store的交易。

Initialization / Getting Started

首先你应该在你的程序里require一下store模块store = require("store")

然后,你需要调用 store.init 函数指定一个listener来处理交易回调(下面会详细介绍)

store.init( listener )

你应该在你的程序完成启动后,尽快调用 store.init() 。原因是App Store希望积极确保任何未完成的交易,能够尽可能完成。如果一个交易在你程序运行的最后时间被中断(比如来电话或者网络中断),用户应该可以继续完成这笔交易。通过调用 store.init(),你的app通知商店,你已经准备好处理交易的回调。

获取关于可用产品的销售信息

Corona提供 store.loadProducts() 来取得关于可用物品的销售信息。这包括每个物品的价格,一个本地化的名称,一个本地化的描述。然而,Apple App Store不会提供一种方法来让你查询所有可用的产品。因此,你的代码必须包括(或生成)所有物品的产品标识符。

store.loadProducts( arrayOfProductIdentifiers, listener )

• arrayOfProductIdentifiers -- 一个每个元素都包含一个字符串的lua数组,每个字符串都是你想知道的应用内物品的产品标识符 。

• listener -- 一个回调函数,当从商店完成产品信息的获取,这个函数才会被调用。

产品的ID就是你在iTunes Connect中输入的那些。典型的惯例是,用你的bundle id再追加上物品名,例如(com.anscamobile.NewExampleInAppPurchase.MyNonConsumableItem)

loadProductsCallback listener回调中,得到的event有下列属性:

• event.products -- 一个lua数组,其每个元素包含一个lua table:包含多个产品信息,例如标题,描述,价格和产品标识符

• event.invalidProducts -- 一个lua数组,其每个元素包含一个字符串,这个字符串就是你请求的产品标识符。这里你只会获得你请求的,但实际上无效或者不存在的条目。


event.products 数组中每个条目支持下列字段:

• title -- 条目的本地化名称。

• description -- 条目的本地化描述。

• price -- 条目的价格(一个数字)

• productIdentifier -- 产品标识符


这里有一个简单的代码例子:

function loadProductsCallback( event )

print("showing products", #event.products)

for i=1, #event.products do

local currentItem = event.products[i]

print(currentItem.title)

print(currentItem.description)

print(currentItem.price)

print(currentItem.productIdentifier)

end

print("showing invalidProducts", #event.invalidProducts)

for i=1, #event.invalidProducts do

print(event.invalidProducts[i])

end

end



arrayOfProductIdentifiers =

{

"com.anscamobile.NewExampleInAppPurchase.MyConsumableItem",

"com.anscamobile.NewExampleInAppPurchase.MyNonConsumableItem",

"com.anscamobile.NewExampleInAppPurchase.MySubscriptionItem",

}

store.loadProducts(arrayOfProductIdentifiers,loadProductsCallback)


如果需要你的产品列表是动态的,Apple建议你在你自己的服务器上提供一个你的app可以获取的最新的产品列表。

通常你会借助回调这个机会来创建和显示一个UI,使用户可以浏览和购买物品。

可以购买了吗?

iOS设备有一个禁止购买的设置。这是为了阻止小孩在没有得到父母允许的情况下意外购买而设的。Corona提供一个API来检查是否可能进行购买。提前使用这个检查一下,可以避免你的用户浏览了你很多购买步骤,结果最后一步发现购买被禁用了。

store.canMakePurchases

如果购买被允许返回true,否则false。

购买产品

为了开始一个购买,Corona提供 store.purchase()。

store.purchase( arrayOfProducts )

• arrayOfProducts -- 一个lua数组指向你想购买的产品。每个元素包含一个字符串(产品标识符)或一个lua table(和通过 loadProductsCallback listener传回的 event.products数组的元素字段一样)

这个函数会发出购买请求到应用商店。你在 store.init()中指定的listener将会在商店完成交易的处理后,被调用。

注意:目前,没有明确的API可以确定可消费物品的数量。然而,作为一个后门,你可以多次把产品放在数组中,然后Corona在幕后设置数量。

(Transaction=交易)

Transaction Listener Callback Events

调用 store.init() 来让你的程序里的listener处理来自AppStore的交易回调。 这个listener应该处理下面所有的情况:

• 一个物品被购买 (通过store.purchase())

• 一个购买交易被用户取消 (在store.purchase() 被调用之后)

• 因为各种原因一个购买交易失败了 (通过 store.purchase())

• 一个物品在之前app被打断前被购买了(也许因为接听一个来电),而app再次运行起来时App Store试着恢复/完成这个交易。

• 一个 A restore already purchased items request was initiated (通过 store.restore(), 下面会解释)


从交易回调监听器( transaction callback listener)得到的event有下列属性:

event.transaction : 一个包含交易信息的对象。


交易对象支持下面的只读属性:

• state -- 一个包含交易状态的字符串。有效值是 "purchased", "restored", "cancelled", 和 "failed"。

• productIdentifier -- 和交易关联的产品标识符。

• receipt -- 从Store返回的唯一收据。这将会返回一个十六进制字符串。

• identifier -- 从Store返回的一个唯一的交易标识符,是一个字符串。

• date -- 交易发生时的日期。

• originalReceipt -- 基于最初购买尝试,从商店返回的一个唯一收据。 这大多数和修复有关。这也是一个十六进制字符串。

• originalIdentifier -- 基于最初购买尝试,从商店返回的一个唯一交易标识符。 这大多数和修复有关。这也是一个字符串。

• originalDate -- 原始交易发生的日期。 这大多数和修复有关。

• errorType -- 当state是“fail”时,发生的错误类型。(一个字符串)

• errorString -- 当在“fail”情况下,更详细的错误描述。


你收到一个交易事件后,由你来决定要做什么。例如,如果用户成功购买了一个物品,你可以记录这个信息在一个偏好文件里,以解锁用户使用这个物品的能力。这个文件将来应该被引用,好在将来要知道这个物品你已经购买过了。简单来说,如果必须下载内容,你可以在这里开始下载。

在你处理完交易后,你必须对你的交易对象调用store.finishTransaction() 。如果你不这么做,AppStore将认为你的交易被打断了,并且试着在下次应用启动时恢复之。

store.finishTransaction( transaction )

恢复购买的物品

擦掉设备上信息、或者购买了新的设备的用户,可能希望恢复他们之前买过的物品,而不用再次为之付费。 store.restore() API开始这个处理。被恢复的交易将调用你之前用 store.init()注册的 transactionCallback listener。这时交易state将是“restored”,你的app将会再次使用交易对象的 originalReceipt, originalIdentifier, 和 originalDate字段。

Transaction Callback Example

function transactionCallback( event )

local transaction = event.transaction

if transaction.state == "purchased" then

print("Transaction succuessful!")



elseif transaction.state == "restored" then

print("Transaction restored (from previous session)")

print("productIdentifier", transaction.productIdentifier)

print("receipt", transaction.receipt)

print("transactionIdentifier", transaction.identifier)

print("date", transaction.date)

print("originalReceipt", transaction.originalReceipt)

print("originalTransactionIdentifier", transaction.originalIdentifier)

print("originalDate", transaction.originalDate)



elseif transaction.state == "cancelled" then

print("User cancelled transaction")



elseif transaction.state == "failed" then

print("Transaction failed, type:", transaction.errorType, transaction.errorString)



else

print("unknown event")

end



-- Once we are done with a transaction, call this to tell the store

-- we are done with the transaction.

-- If you are providing downloadable content, wait to call this until

-- after the download completes.

store.finishTransaction( transaction )

end



store.init( transactionCallback )



-- Might try buying something here:

-- store.puchase"com.anscamobile.NewExampleInAppPurchase.MyNonConsumableItem" }

-- Or might try restoring here:

-- store.restore()

Additional Notes & Documentation

在App中,购买并不容易设置。你可能会发现你比实际写代码,花费了更多的时间在iTunes Connect中设置东西,以及创建 Provisioning Profiles。这里有一些提示和连接,会在这方面帮助到你。

创建一个新的App ID和 provisioning profile,并使用它。使用完整合格的bundle标识符,比如 com.yourdomain.yourapp。不要使用通配符例如com.*。

一些人声称设置你的应用内支付和在Apple网络中传播,需要24个小时。这意味着你应该提早在iTunes Connect里把应用程序的各种东西设置好,以便到时候可以开始测试代码,而不必等待。不幸的是,你不知道如果有错误,到底是网络传播延迟还是有些地方,这就是为什么你应该提早把这些设置好的原因。

记住当测试的事后,创建一个测试用户帐号,然后在你的iOS设备设置->store中登出你自己的帐号。这里先别登入你的测试帐号;等一下知道你的app运行,并且你被提示要这样做时,你再登入你的测试帐号。当你用Corona构建你的产品时,确保你使用的是正确的 provisioning profile(你用完整合格的 bundle identifier 为这个应用创建的那个)。


Apple Links

• In App Purchase Programming Guide

• Technical Note TN2259: Adding In App Purchase to your iOS Applications

• iTunes Connect Frequently Asked Questions > Manage Your In App Purchases

Other Links

• In App Purchases: A Full Walkthrough

• Things I learned implementing my first InAppPurchase
<< 五分钟学会Corona(二十) - 异步HTTP五分钟学会Corona(二十二) - System and OS >>

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

最近发表

Powered By Z-Blog 1.8 Walle Build 100427 Copyright 2011-2015 BuildApp.Net. All Rights Reserved.