Adobe Gaming SDK 内置ProductStore详解

来源:互联网 发布:东莞网络推广 编辑:程序博客网 时间:2024/05/02 04:51

Adobe在去年岁末发布了Gaming Develop Tool,其中一个内容是苹果内支付的原生扩展ProductStore。我在自己的项目里反复试验了这个ANE,所以等了很久才写这篇教程,旨在帮助初学者理解苹果应用内支付的一些流程,以及学会使用这个ANE的几个关键API。

本文适合的人群:
使用Adobe AIR进行iOS游戏和应用开发的ActionScript 3开发者。
有应用内支付需求的开发者
会使用ADT打包iPA

阅读本文不需要具备的知识:
Objective C

—————————————————-
下载安装ProductStore
—————————————————-

用你的Adobe帐号登陆Adobe创意云(Creative Cloud),然后在下面的页面下载Adobe Gaming SDK:
https://www.adobe.com/products/gaming/tools.html

Screen-Shot-2013-01-04-at-10.44.43-AM.png



下载安装后,打开安装路径下的Native Extensions(ANEs)文件夹,可以看到Adobe官方提供的免费ANE。其中Product Store.ane是内支付扩展,把它拷贝到你的项目下的一个合理路径,然后用开发工具引用它,就可以进行开发了。

Screen-Shot-2013-01-04-at-10.50.45-AM.png



小贴士:如果你的开发工具不支持直接引用ANE文件,如Flash Builder 4.6以前的版本。可以把ANE文件扩展名修改成SWC后再引用。

——————————————————–
应用内支付的工作原理
——————————————————–

如果要使用ProductStore,就必须要先了解苹果内支付流程是怎样的。下面摘自苹果开发者文档的两个流程图,很好解释了这个问题:

本地应用内支付流程图
built_in_store_diagram.png



上图适用于非消费型商品,也就是只需用户一次购买终身享用的那种;下图是消费型商品,一般情况下需要开发者自己架设服务器来保存用户的购买记录。

有第三方服务器介入的支付流程图

store_transactions.png



但无论是哪种架构,内支付的基本流程如下:
请求商品信息 -> 购买商品 -> 验证收据 -> 购买成功

由此可见,应用程序需要做以下5件事情:

1, 请求商品列表和详细信息(提交商品ID,处理结果)
2, 展示商品列表和详细信息(用户界面,提供购买按钮)
3, 处理用户购买请求 ( 提交商品ID,处理结果)
4, 验证收据(提交收据,处理结果)
5, 用户反馈

针对这些工作,ProductStore给开发者提供了完整的API
——————————————————–
ProductStore的API
——————————————————–
在写内支付第一行代码之前,一定要到itunesconnect.apple.com上创建应用内支付商品,否则商品ID无效,应用也就无法测试。

准备妥当后,再打开安装目录下的Doc文件夹,可以看到API文档,可惜这份文档内容还十分初浅,连英文描述都很少,更别提中文了。好在内支付的API并不多,所以我们只要关注这几个类:

ProductStore
ProductEvent
Product
Transaction
TransactionEvent

朋友们只要注意以下几点,就能保证你的内支付程序运作无误。
————————————————————–
(一)在应用程序运行后,尽早创建一个ProductStore的Singleton实例,并保持它存在于整个应用的生命周期内。
————————————————————–

1

productStore = new ProductStore();

给productStore添加以下的事件侦听:
ProductEvent.PRODUCT_DETAILS_SUCCESS :商品列表获取成功ProductEvent.PRODUCT_DETAILS_FAIL:商品列表获取失败
TransactionEvent.PURCHASE_TRANSACTION_SUCCESS:交易成功 TransactionEvent.PURCHASE_TRANSACTION_CANCEL:交易取消
TransactionEvent.PURCHASE_TRANSACTION_FAIL:交易失败 TransactionEvent.FINISH_TRANSACTION_SUCCESS:结束交易成功
TransactionEvent.RESTORE_TRANSACTION_SUCCESS:恢复交易成功
TransactionEvent.RESTORE_TRANSACTION_FAIL:恢复交易失败
TransactionEvent.RESTORE_TRANSACTION_COMPLETE:恢复交易完成

具体含义在下面讲解。
————————————————————–
(二)尽早请求商品信息,并保存在内存中
————————————————————–

使用下面的API可以使用商品ID来请求商品的详细信息:

1

2

var productsArray:Array = ["package1","package2","package3"]
productStore.requestProductsDetails(productsArray);

如果productsArray里定义的每一个商品ID都在itunesconnect.apple.com成功设置,并且给productStrore添加了ProductEvent.PRODUCT_DETAILS_SUCCESS侦听,那么就可以在侦听器里成功获取这些商品的详细信息。

  1. private function onProductsReceived(e:ProductEvent):void{
  2.       products = e.products
  3.       for each(var p:Product in products){
  4.               //这里获取每一个商品的信息
  5.       }
  6. }
复制代码

商品信息被ANE封装在一个Product类中,属性如下:
identifier: 商品ID
title:商品名称
description:描述文字
price:商品价格(已经折合为用户商店的本地货币单位)
priceLocale:商品价格本地化信息(用来获取货币单位的显示),如果你的应用需要在中国玩家设备上显示”CNY 6″ , 但是在美国玩家那儿显示”USD 0.99″,那么你就需要用到这个属性。(别忘了有些国家的货币数值可能比较大,比如岛国,所以要给你的文本框留足位置)

————————————————————–
(三)有关交易的触发和维护
————————————————————–

调用下面的API可以触发购买的交易请求:

1

productStore.makePurchaseTransaction("package1", 1);

上面代码向Store发送了一个购买请求,商品ID是package1,数量为1。与此同时,ANE向设备中的应用商店发送了一个购买行为,由设备系统内的应用商店来负责交易的安全。它会先弹出一个原生对话框,让玩家作购买确认;然后负责玩家的安全登陆和密码输入;再去连接苹果的服务器进行交易;最后将得到的结果返回给应用程序。

从程序角度来看,每一个交易是一个Transaction。它包含了下面的属性:
identifier:交易ID,每次交易都有一个unique的ID,由应用商店生成。
date:交易时间
error:交易错误信息
originalTransaction:原始交易(针对恢复非消费型商品的交易)
productIdentifier:交易所涉及的商品ID
productQuantity:交易所涉及的商品数量
receipt:交易成功后的收据

(由ANE封装的Product和Transaction类,保存了iOS SDK中StoreKit的原生类属性,连命名都一样)。

关于交易的几个FAQ

(1)如果用户在交易过程中退出应用了怎么办?
设备中的应用商店,维护着一个Transaction队列。每个交易的生命周期不受应用程序的生命周期限制,即使在交易过程中退出,交易依然存在。下次登陆应用并且初始化ProductStore时,应用商店会在第一时间派发事件告知交易结果。这就是为什么我提到要尽早初始化ProductStore。

(2)如何防止用户重复扣款?
对于非消费型商品不存在这个问题,商店不会因为这类商品给用户重复扣款。但是对消费型商品,开发者也不必担心重复扣款的问题。开发者只要在判断了交易成功(包含验证收据)之后结束该交易,则用户就可以再次购买该商品。否则每次购买同样的商品都会产生一个相同的交易ID,应用商店会提示“您已经购买该商品,但是并没有下载”这样的信息。至于如何结束交易会在接下来的内容中说明。

TransactionEvent.PURCHASE_TRANSACTION_SUCCESS
下面是一段处理成功交易的代码范例,开发者在得到了交易成功的结果之后不要急于给玩家提供相应的服务。为了保证该交易是合法的而非来自于第三方软件的造假行为,需要拿着收据去苹果网站上验证。验证收据会在稍后说明。



  1. private function purchaseTransactionSucceeded(e:TransactionEvent):void{
  2.         var i:uint=0;
  3.         var t:Transaction;
  4.         while(e.transactions && i < e.transactions.length){
  5.                 t = e.transactions[i];
  6.                 i++;
  7.                 verifyReceipt(t.identifier, t.productIdentifier, t.productQuantity, t.receipt);
  8.         }
  9. }
复制代码



TransactionEvent.PURCHASE_TRANSACTION_CANCEL
TransactionEvent.PURCHASE_TRANSACTION_FAIL        

当用户取消交易或者交易失败的时候,或者一个新的交易请求属于重复购买行为。应用商店会派发Cancel或者Fail这两个事件。它们都可以用下面的代码来处理,使用ProductStore.finishTransaction这个API来结束这笔交易。调用这个API会将该交易从系统维护的交易队列中移除。

  1. private function purchaseTransactionCanceled(e:TransactionEvent):void{
  2.         var i:uint = 0;
  3.         while(e.transactions && i < e.transactions.length){
  4.                 var t:Transaction = e.transactions[i];
  5.                 i++;
  6.                 productStore.finishTransaction(t.identifier);
  7.         }
  8. }
复制代码

—————————————————————-
(四)验证收据
—————————————————————-
交易收据以字符串的形式保存在Transaction类的receipt属性里,开发者可以选择在客户端提交验证,也可以选择让自己的服务器来发送验证。

验证收据的目的是检查该交易的合法性,防止无效的购买。验证的方式是将收据以JSON对象的方式发送到苹果官方的验证地址,然后判断返回的结果。

强烈推荐先用Base64把收据编码然后再发送。

  1. var encodedReceipt:String = Base64.encode(receipt);
  2. var req:URLRequest = new URLRequest("https://sandbox.itunes.apple.com/verifyReceipt");
  3. req.method = URLRequestMethod.POST;
  4. req.data = "{\"receipt-data\" : \""+ encodedReceipt +"\"}";
  5. var loader:URLLoader = new URLLoader(req);
  6. loader.addEventListener(Event.COMPLETE,onReceiptComplete);
  7. loader.addEventListener(IOErrorEvent.IO_ERROR, onReceiptError);
复制代码

响应的结果也是一个JSON格式的对象:

  
  1. {
  2.     "status" : 0,
  3.     "receipt" : { (receipt here) }
  4. }
复制代码

注意:应用正式提审之前要把验证收据的地址改为https://buy.itunes.apple.com/verifyReceipt

status只要是0就说明该收据有效,否则无效。苹果对收据的验证没有时效性,它不负责该收据的生命周期,所以发送相同的收据永远会得到同样的结果。作为第三方服务器,需要使用交易ID对交易作记录,这样可以避免同一个收据的两次成功验证导致的两次购买成功的问题。

Gaming SDK包含了一个ProductStore的案例,各位可以在安装路径下找到。这个案例在验证收据的时候有一个bug,它使用了一个第三方的Base64类,却没有提供该类包,所以会出现编译错误。大家要注意这点,自己找一个Base64类来代替就可以了。


转自:http://bbs.9ria.com/thread-171203-1-1.html


0 0