购买 In-app Billing 商品
一旦你的应用连接上了 Google Play,你就可以初始化内购商品的购买请求了。Google Play 提供了结算接口,可以让用户进入使用他们的支付方式,所以你的程序不必直接处理支付交易。
When an item is purchased, 当一个商品被购买后,Google Play 会认为这个用户已经拥有了此商品,并且直到这个商品被”消耗“后才会让用户再购买一个有相同商品ID的商品。你可以在你的程序里控制如何消耗商品,消耗后再告诉Google Play,Google Play会让这个商品再次可以购买。
你也可以通过向Google Play查询,快速获取用户已经购买的商品列表。这个方式很有用。举个例子,在用户启动你的应用时,你想把用户已经购买的商品交给用户.注1
购买一个商品
通过调用 IabHelper
的 launchPurchaseFlow(Activity, String, int, OnIabPurchaseFinishedListener, String) 方法从你的应用中开始一个购买请求。你必须在你
Activity的主线程里调用这个方法。下面是对
launchPurchaseFlow
方法中使用参数的解释:
- 第一个参数是调用的
Activity。
- 第二个参数是要购买商品的商品ID(也称做商品的SKU)。确保你用的是ID而不是商品名字。此前你应该已经在开发者控制台定义并且激活了这个商品,否则这个商品将不会被识别。
- 第三个参数是请求码。这个码可以是任何正整数。Google Play 会把这个码连同购买回应一起返给调用
Activity的
onActivityResult
方法。 - 第四个参数是一个监听器(listener)。当购买操作完成以及处理收到Google Play的购买回应时,这个监听器会被通知。
- 第五个参数含有一个‘developer payload’的字符串,你可以用来发送有关一个订单的额外信息(可以是一个空字符串)。通常这个参数会以一个唯一标示这次购买请求的字符串token来使用。如果你指定了一个字符串类型的值,Google Play会把这个值连同购买回应一起发给你。随后,当你对这个商品进行查询时,Google Play也会把这个字符串连同商品详细信息一起返给你。
安全建议: 一个好的做法就是你传一个有助于你的程序识别是哪个用户购买了商品的字符串,这样你以后就可以验证这个用户的购买是否是真实的。对于可消耗的商品,你可以使用一个随机生成的字符串,对于不可消耗的商品,你应该使用一个唯一标示用户的字符串。
下面的例子随便使用了一个请求码10001和一个加密的 developer playload 字符串,展示如何购买一个商品ID为 SKU_GAS的商品。
mHelper.launchPurchaseFlow(this, SKU_GAS, 10001, mPurchaseFinishedListener, "bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ");
If the purchase order is successful, 如果购买成功,Google Play会把返回的数据存到一个 Purchase对象中,这个对象会传给listener。
下面的例子展示了根据此次购买是否成功以及用户购买的是 gas 还是 premiun upgrade,在listener所做的处理。在这个例子中,gas是一个可以购买多次的内购商品,所以你应该在允许用户再次购买之前消耗掉这个商品。学习如何消耗商品,查看 消耗商品 部分。 这个 premium upgrade 是一个一次性购买商品,所以你不必消耗它。购买成功后立刻更新UI是很好的做法,这样你的用户就可以看到他们新购买的物品。
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() { public void onIabPurchaseFinished(IabResult result, Purchase purchase) { if (result.isFailure()) { Log.d(TAG, "Error purchasing: " + result); return; } else if (purchase.getSku().equals(SKU_GAS)) { // consume the gas and update the UI } else if (purchase.getSku().equals(SKU_PREMIUM)) { // give user access to premium content and update the UI } } };
安全建议: 当你从 Google Play收到购买返回消息时,一定要检查返回Purchase对象中的数据签名,订单号和developerPayload,确保是你想要的值。你应该验证订单号
orderId 是你先前没有处理过的独一无二的值,以及
developerPayload
字符串符合你先前发送购买请求设置的token(译者注:发送的developerPayload是加密的,可能是MD5,也可能是Base64,因为这个payload是原样返给你的,你解密对比一下是不是原值)。 作为更长远的安全措施,你应该在你自己的安全服务器做验证。P.S.这段内容和我先前写的博客里的建议差不多。
查询购买的商品
每次购买成功后,Google Play的内购服务就会把用户的购买数据缓存在本地。一个好的做法就是多通过In-app Billing服务查询用户的购买,举例来说,不论何时程序启动或者恢复,都去查询一下,这样用户当前所拥有的内购商品的情况都可以反映到你程序中。
通过调用 IabHelper
中的queryInventoryAsync(QueryInventoryFinishedListener)
方法来获取用户的购买信息。
这个QueryInventoryFinishedListener
参数设置了一个监听器,当查询操作完成以及处理查询回应结果时,这个监听器都会收到通知。在你程序的主线程调用这个方法是安全的。
mHelper.queryInventoryAsync(mGotInventoryListener);
如果查询成功,查询结果就会存到一个 Inventory
对象中并传回给监听器。In-app Billing 服务只会返回当前登陆设备用户所完成的购买信息。
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() { public void onQueryInventoryFinished(IabResult result, Inventory inventory) { if (result.isFailure()) { // handle error here } else { // does the user have the premium upgrade? mIsPremium = inventory.hasPurchase(SKU_PREMIUM); // update UI accordingly } } };
消耗商品
你可以通过使用 In-app Billing Version 3 API 来追踪购买物品存在Google Play上的所有权信息。一旦一个物品被购买,它就会被认作“拥有”状态,当处在此状态时就不可以再次从Google Play购买。对于这个物品,你必须向Google Play发送一个消耗请求,这样Google Play才可以重新让这个商品可以被买。所有的受管理内购商品都是可消耗的。在你的程序里如何使用这个消耗机制取决于你。一般来说,你会为那些短暂起作用,用户可能想多次购买的商品实现消耗(例如,游戏内货币或者可重复使用的游戏Token),而像那些购买一次就可以提供持久效果的商品就不需要实现消耗(例如,额外升级)。
你负责控制和追踪如何内购商品给用户。例如,如果用户购买了游戏内货币,你就应该把购买的货币数量更新到玩家的财产中。
安全建议: 用户购买可消耗商品成功后,在把商品给用户前,你要先发送一个消耗请求,确保你从Google Play收到消耗成功的回应后才可以把商品发给用户。
为了记录购买消耗,你可以调用IabHelper
中的 consumeAsync(Purchase, OnConsumeFinishedListener)
方法。这个方法中的第一个参数是 Purchase
对象,代表的是消耗的物品。 第二个参数是 OnConsumeFinishedListener,当消耗操作完成以及处理来自Google Play的消耗回应时,都会通知这个listener。
可以在程序主线程调用这个方法。
在下面这段代码中,你想消耗用户先前在你程序中购买的气体道具。
mHelper.consumeAsync(inventory.getPurchase(SKU_GAS),
mConsumeFinishedListener);
下面代码展示了如何实现 OnConsumeFinishedListener
.
IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() { public void onConsumeFinished(Purchase purchase, IabResult result) { if (result.isSuccess()) { // provision the in-app purchase to the user // (for example, credit 50 gold coins to player's character) } else { // handle error } } };
程序启动时检查可消耗物品
一个重要的事,就是在用户启动你应用的时候检查可消耗物品。通常来说,你会首先在In-app Billing服务中查询用户已经购买了商品信息(v通过queryInventoryAsync
),然后通过Inventory获取可消耗 Purchase
对象。如果你的程序检测到用户拥有可消耗物品,不管是那种,你都应该马上向Google Play发送一个消耗请求,随后把这个物品发给用户。 看看TrivialDrive
例子是如何实现在应用启动时做这个检测的。
注1:原文 This is useful, for example, when you want to restore the user's purchases when your user launches your app.