简体   繁体   English

Android In-App Billing: Purchase state 在订单取消后保持“已购买”状态

[英]Android In-App Billing: Purchase state stays "purchased" after order cancelation

I'm currently testing my InApp billing mechanism (using the InApp Billing version 3 API, therefore taking the TrivialDrive example as reference).我目前正在测试我的 InApp 计费机制(使用 InApp Billing 版本 3 API,因此以 TrivialDrive 示例作为参考)。

I have one managed item, which is upgrade to premium version.我有一个管理项目,升级到高级版本。

Now, purchasing the item with my test account works, but when I do a cancellation of the entire order in Google checkout afterwards, my code still tells me that the item is purchased an therefore grants the premium features.现在,可以使用我的测试帐户购买该商品,但是当我之后在 Google 结帐中取消整个订单时,我的代码仍然告诉我该商品已购买,因此授予高级功能。

Here is how I check for the purchase in my MainActivity.以下是我在 MainActivity 中检查购买的方式。 I do not save the purchase state locally somewhere, as I understood that the with the billing API v3, you can query for purchases ad hoc as needed.我没有在本地某处保存购买 state,据我所知,使用账单 API v3,您可以根据需要临时查询购买。

@Override
    protected void onStart() {
        // TODO Auto-generated method stub
        super.onStart();

        iabHelper = new IabHelper(this, Helper.getPKey());
        iabHelper.enableDebugLogging(true);

        iabHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {

            @Override
            public void onIabSetupFinished(IabResult result) {
                Log.d("IAB", "SETUP FINISHED");

                if(!result.isSuccess())
                {
                    Log.d("IAB", "SETUP NOT OK");
                    return;
                }
                else
                    Log.d("IAB", "SETUP OK");

                iabHelper.queryInventoryAsync(
                    new QueryInventoryFinishedListener() {

                        @Override
                        public void onQueryInventoryFinished(IabResult result, Inventory inv) {
                            Log.d("IAB", "Query inventory finished.");
                            if (result.isFailure()) {
                                Log.d("IAB","Failed to query inventory: " + result);
                                return;
                            }

                            Log.d("IAB", "Query inventory was successful.");

                            // Do we have the premium upgrade?
                            boolean mIsPremium = inv.hasPurchase(Helper.premiumSku);
                            Purchase p = inv.getPurchase(Helper.premiumSku);
                            if(p != null)
                                Log.d("IAB PURCHASE STATE", IabHelper.getResponseDesc(p.getPurchaseState()));
                            else
                                Log.d("IAB PURCHASE STATE", "Purchase is null");

                            Log.d("IAB", "User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));


                        }
                    }                       

                );              
            }
        });       
    }

I keep getting getPurchaseState = 0, which means is Purchased, even one hour after I cancelled the order.我一直收到 getPurchaseState = 0,这意味着已购买,甚至在我取消订单后一小时。 Why?为什么?

After having waited for about 12 hours and having tried everything suggested here, I was still facing the same issue.在等了大约 12 个小时并尝试了这里建议的所有内容后,我仍然面临同样的问题。 What did the trick for me was the following adb command:以下 adb 命令对我有什么帮助:

adb shell pm clear com.android.vending adb shell pm clear com.android.vending

I know this is a year old, but none of the answers/tips presented helped me so I thought I would add my solution.我知道这是一岁了,但是提供的答案/提示都没有帮助我,所以我想我会添加我的解决方案。

First, I was experiencing the same issue.首先,我遇到了同样的问题。 Namely, made a test purchase, cancelled it, still received a purchase state indicating valid purchase.即,进行了测试购买,取消了它,仍然收到指示有效购买的购买状态。

What I forgot was that I recently switched the 'License Test Response' field on the settings pane of the Google Play Developer Console from 'RESPOND_NORMALLY' to 'LICENSED'我忘记了我最近将 Google Play Developer Console 设置窗格上的“License Test Response”字段从“RESPOND_NORMALLY”切换为“LICENSED”

After switching it back to 'RESPOND_NORMALLY', the purchase state of the cancelled purchase was correctly returned as such.将其切换回“RESPOND_NORMALLY”后,取消购买的购买状态已正确返回。

So, you might want to check that before you try waiting for days因此,在尝试等待几天之前,您可能需要检查一下

Step 1. Wait approximately 10 minutes;步骤 1. 等待大约 10 分钟; Until you see the "cancelled order" was delivered.直到您看到“取消的订单”已送达。 in your google wallet.在你的谷歌钱包里。

Sep 15 11:28 AM Cancelled The order was delivered. 9 月 15 日上午 11:28 取消 订单已送达。

Sep 15 11:18 AM Cancelled You cancelled this order. 9 月 15 日上午 11:18 取消 您取消了此订单。 Reason: Customer request to cancel.原因:客户要求取消。

Step 2. Logout your test google account on the device and then re-login.步骤 2. 在设备上注销您的测试谷歌帐户,然后重新登录。

At least that solved my problem.至少这解决了我的问题。

This problem also occures when using the app on another device with the same account.在使用同一帐户的另一台设备上使用该应用程序时也会出现此问题。 The item is not received as purchased until the device is restarted, even after hours.在设备重新启动之前,即使在数小时后,也不会收到购买的商品。 If trying to purchase again, the google wallet dialog says "item already owned".如果尝试再次购买,谷歌钱包对话框会显示“项目已拥有”。 The return code from the iabHelper still is "user cancelled" cause the real response from the purchase activity is not given back, just written in the debug log. iabHelper 的返回码仍然是“用户取消”,因为购买活动的真实响应没有返回,只是写入调试日志中。

else if (resultCode == Activity.RESULT_CANCELED) {
        logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode));
        result = new IabResult(IABHELPER_USER_CANCELLED, "User canceled.");
        if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null);
    }

So its not possible to react to this google billing dialog cause we are always getting the same result IABHELPER_USER_CANCELED, even if the dialog said "item already owned".所以不可能对这个谷歌计费对话框做出反应,因为我们总是得到相同的结果 IABHELPER_USER_CANCELED,即使对话框说“项目已经拥有”。

Edit:编辑:

I fix it with this:我用这个修复它:

else if (resultCode == Activity.RESULT_CANCELED) {
        logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode));
        if(responseCode == 7) 
            result = new IabResult(BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED, "Item already owned.");
        else                                                                                             
            result = new IabResult(IABHELPER_USER_CANCELLED, "User canceled.");
        if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null);
    }

So now if the response from the billing dialog is 7 as "Item already owned" i report it back to my listener.所以现在如果来自计费对话框的响应是 7 作为“项目已经拥有”,我会将其报告给我的听众。

What you can use is the autoRenewing field of the purchase data.您可以使用的是购买数据的autoRenewing字段。 According to the documentation :根据文档

autoRenewing: Indicates whether the subscription renews automatically. autoRenewing:表示订阅是否自动续订。 If true, the subscription is active, and will automatically renew on the next billing date.如果为 true,则订阅处于活动状态,并将在下一个计费日期自动续订。 If false, indicates that the user has canceled the subscription .如果为 false,则表示用户已取消订阅

And this field get updated immediately after the cancellation.取消后,该字段会立即更新。

if I see correctly the reference code in the trivialdrivesample is wrong, which would be a shame for the official reference project for in app billing.如果我没看错,trivialdrivesample 中的参考代码是错误的,这对于应用内计费的官方参考项目来说是一种耻辱。

if purchase == null it just means it has never been purchased.如果 purchase == null 则表示它从未被购买过。 To get the real information you have to call要获得真实信息,您必须致电

purchase.getPurchaseState()

according to here根据这里

purchaseState The purchase state of the order. purchaseState 订单的购买状态。 Possible values are 0 (purchased), 1 (canceled), 2 (refunded), or 3 (expired, for subscription purchases only).可能的值为 0(已购买)、1(已取消)、2(已退款)或 3(已过期,仅适用于订阅购买)。

It's already well answered in the Google official docs.谷歌官方文档中已经给出了很好的答案。 Copying the words here.复制这里的话。

When the user cancels a subscription, Google Play does not offer a refund for the current billing cycle.当用户取消订阅时,Google Play 不会提供当前计费周期的退款。 Instead, it allows the user to have access to the cancelled subscription until the end of the current billing cycle, at which time it terminates the subscription.相反,它允许用户在当前计费周期结束之前访问已取消的订阅,届时它会终止订阅。 For example, if a user purchases a monthly subscription and cancels it on the 15th day of the cycle, Google Play will consider the subscription valid until the end of the 30th day (or other day, depending on the month).例如,如果用户购买了月度订阅并在周期的第 15 天取消,Google Play 会认为订阅有效期至第 30 天(或其他日期,取决于月份)。

That should explain it all.这应该能说明一切。 getPurchase() will still return the purchase data till the end of the current subscription cycle. getPurchase()仍将返回购买数据,直到当前订阅周期结束。

I found the following section in the documentation (IAB API v2), but I am not sure if this can be used for IAB API v3.我在文档(IAB API v2)中找到了以下部分,但我不确定这是否可以用于 IAB API v3。 The broadcast might still be sent though.广播可能仍会被发送。

"... your application can receive an IN_APP_NOTIFY broadcast intent when Google Play receives a refund notification from Google Wallet. In this case, Google Play sends an IN_APP_NOTIFY message to your application. Your application can handle this message the same way it handles responses from an application-initiated REQUEST_PURCHASE message so that ultimately your application receives a PURCHASE_STATE_CHANGED message that includes information about the item that has been refunded. The refund information is included in the JSON string that accompanies the PURCHASE_STATE_CHANGED broadcast intent. Also, the purchaseState field in the JSON string is set to 2." “...当 Google Play 收到来自 Google Wallet 的退款通知时,您的应用程序可以收到 IN_APP_NOTIFY 广播 Intent。在这种情况下,Google Play 会向您的应用程序发送 IN_APP_NOTIFY 消息。您的应用程序可以像处理来自应用程序启动的 REQUEST_PURCHASE 消息,以便您的应用程序最终收到 PURCHASE_STATE_CHANGED 消息,其中包含有关已退款项目的信息。退款信息包含在伴随 PURCHASE_STATE_CHANGED 广播意图的 JSON 字符串中。此外,还有 JSON 中的 purchaseState 字段字符串设置为 2。”

from: http://developer.android.com/google/play/billing/v2/api.html#billing-action-notify来自: http : //developer.android.com/google/play/billing/v2/api.html#billing-action-notify

I noticed the exact same thing:我注意到完全相同的事情:

Making an in-app purchase with a test account -> refunding the purchase with removing access -> getPurchaseState still returns Purchased (even after relogin and restart) and thus the access to the premium features is not removed in my app.使用测试帐户进行应用内购买 -> 通过删除访问权限退还购买 -> getPurchaseState 仍返回已购买(即使在重新登录并重新启动后),因此在我的应用中不会删除对高级功能的访问。

But when I tested the same thing with a real purchase:但是当我用实际购买测试同样的东西时:

Customer made a real purchase -> a couple of weeks later I refunded it -> Customer did not have access to the premium features of my app anymore.客户进行了真正的购买 -> 几周后我退款了 -> 客户无法再访问我的应用程序的高级功能。

So could it be, that this is only a problem for test purchases?那么,这可能只是试购的问题吗?

As of 2022 March 06, Billing Client version 4 API, you might still need to wait a few hours after cancellation until a purchased item is cancelled in Google Play.自 2022 年 3 月 6 日起,Billing Client 版本 4 API,您可能仍需要在取消后等待几个小时,才能在 Google Play 中取消购买的商品。

Sometimes I saw cleaning the project also helps (In Android Studio: Build menu > Clear project)有时我看到清理项目也有帮助(在 Android 工作室:构建菜单 > 清除项目)

However, in case of subscriptions you can also check and adjust the "Grace period" for your product in Google Play Console:但是,如果是订阅,您还可以在 Google Play 控制台中检查和调整您产品的“宽限期”: 在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM