我已使IAB v3正常运行,并且能够购买托管项目。但是,为了继续进行开发和测试,我想退还所购的产品,这样我可以尝试再次进行相同的购买。我登录了Google Checkout商家帐户,并成功退还了购买的款项。但是,该应用仍然认为用户已经购买了该商品。自从我退款以来已经有几个星期了,所以这不是延迟问题。
基本上,在我的QueryInventoryFinishedListener
实现中,即使退款后inventory.hasPurchase(SKU_REMOVE_ADS)
始终返回true(SKU_REMOVE_ADS
是我所售商品的SKU)。我期望退款处理后,它会返回false。
如果您查看'Handling Refunds' section of the IAB reference,它表示您的应用程序需要监听IN_APP_NOTIFY消息。但是documentation for IN_APP_NOTIFY特定于应用内结算的v2。它似乎在v3中不可用,因为在v3引用中的任何地方都没有提及它,我也不能在他们用来演示IAB v3的sample TrivialDrive app中找到任何引用。
那么IAB v3是否支持退款/取消购买?有没有人尝试过并使其正常工作的?
最佳答案
就Google Play而言,消耗品和非消耗品之间确实没有区别;这种区别完全基于您在应用程序中实现的功能。因此,即使您要测试的SKU打算是非消耗性的(例如,永久性高级升级),出于测试目的,您也可以将其视为消耗品并将其消耗掉,以便再次购买。
一种方便的方法是在应用程序中设置一个临时测试菜单(例如,通过在测试过程中将菜单项添加到应用程序的主选项菜单中),然后让该项目的处理程序为您的IabHelper实例调用invokeAsync()方法,您要再次测试购买的SKU。这将消耗该物品,因此可以立即从您的设备上购买该物品。
当然,您仍然希望从Google Checkout退还购买的款项,这样您就不会再花您自己的钱来测试您的应用了。
我要补充一点,如果您正在使用此类静态值进行测试,那么对于重置测试SKU android.test.purchased而言,ConsumerAsync()似乎也可以正常工作。
关于更新购买状态以反射(reflect)退款,我个人经历(并且有许多其他开发者发布过类似的报告),我通过Checkout手动启动退款(例如,从TrivialDrive应用程序进行测试购买)需要花费几天的时间更改产品的购买状态(更改为INAPP_PURCHASE_STATE_REFUNDED)。
(知道苦难热爱公司,可以在此讨论线程中找到其中一些其他报告:
https://plus.google.com/+AndroidDevelopers/posts/R8DKwZDsz5m)
至少部分原因是Google Play在设备上缓存了购买数据。
以我的经验,重新启动设备有时会导致Google Play从GP服务器刷新其缓存。因此,重启后可能还会检测到由于通过Checkout取消或退款而导致的更改。
如此长的周转期似乎对您不利,因为您不知道用户何时重新启动。但话又说回来,您知道每台设备最终都会重新启动,因此,如果您担心最终会收到退款的用户禁止使用已退款的IAB产品,那么几天的延迟可能并不重要,只要它最终发生。
当然,请记住,这种关于高速缓存将在重新启动后刷新的概念是没有记载的,而且是轶事(到目前为止,就像很多IAB3和TrivialDrive行为一样)。民俗,他们称之为。
触发更新的另一件事是用户尝试购买产品时。购买开始后,系统必须确保该产品尚未拥有,因此它会更新Google Play缓存。以我的个人经验,这总是发生的。但是同样,这不是检查退款的非常实用的方法,因为这将涉及显示未禁止的购买对话框,并且还会显示一条错误消息,告诉用户“您已经拥有此商品”(如果他们确实拥有它)。
当用户在她的一个设备上购买IAB物品,然后尝试在与购买该物品相同的帐户拥有的另一设备上尝试访问该物品时,这很方便。在这种情况下,购买信息通常尚未被缓存。但是您可以在购买对话框中稍加注意,即如果已经购买了该物品,则尝试重新购买应该可以在当前设备上免费使用该物品。有时需要两次(用户启动)的购买尝试才能最终获得IabHelper.BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED响应。是的,有点笨拙,但是我认为从人的角度来说,它可以适本地突出显示消息,并在确认对话框的道歉措辞中告诉他们他们拥有该物品,等等:-))。
实际上,您可以看到Google可能不希望世界上每个IAB应用的每个实例在每次访问该应用的购买数据时都访问其服务器,尤其是考虑到它们正在建议开发人员检查是否存在每次启动该应用程序时都要购买的价格。这也是您应用程序的性能问题-这就是缓存的全部含义。因此,您需要了解更新缓存的触发器,而且我还没有找到一个正式记录过缓存的地方(我们假定在代码中除外)。因此,请准备好将您的双手放在面前,开始在黑暗中摸索。
有关Google Play缓冲的其他信息,请参见以下页面:
Under What Conditions are In-App Billing Version 3 Server Changes Made Available on Client Devices?
我会注意到,在帖子的代码段中,您正在调用stock.hasPurchase(SKU_REMOVE_ADS),但这只会告诉您购买是否在库存对象返回的购买 list 中;它不会告诉您该SKU的购买状态。我知道这是TrivialDrive应用程序使用的方法,但是该应用程序不处理退款和取消。要检测退款和已取消的订单,您将需要以下内容:
Purchase removeAdsPurchase = inventory.getPurchase(SKU_REMOVE_ADS);
if(removeAdsPurchase != null) {
int purchaseStateForRemoveAds = removeAdsPurchase.getPurchaseState();
if(purchaseStateForRemoveAds == 1) {
//Do cancelled purchase stuff here
}
else if(purchaseStateForRemoveAds == 2) {
//Do refunded purchase stuff here
}
}
关于退款和已取消订单的好消息是,完全由开发人员选择,两者都是AFAIK。因此,如果您发现获得这些退款的用户此后能够在较长时间内继续使用您的应用程序,并且如果发现很多用户都在利用此功能,则可以决定是否要继续在其中提供退款所有情况。我最大的猜测是,这不会是一个问题。即使获得退款的某些用户在此后一段时间可以使用您的应用,这也不是什么大不了的事情。
这是为了进行测试,您需要非常快速地重试购买的能力,并且使用consumerAsync()绝对可以实现此目的。