IT story

인앱 결제 테스트 : android.test.purchased 이미 소유

hot-time 2020. 8. 4. 22:51
반응형

인앱 결제 테스트 : android.test.purchased 이미 소유


현재 향후 앱에 대한 인앱 결제를 테스트 중이며 테스트 항목 "android.test.purchased"를 처음으로 "구입"한 후 다시 구매하려고 할 때마다 응답 코드 7이 표시됩니다. 이미이 항목을 소유하고 있음을 의미합니다.

12-15 23 : 02 : 14.149 : E / IabHelper (19829) : 인앱 결제 오류 : 항목을 구매할 수 없음, 오류 응답 : 7 : 항목이 이미 있음

내가 이해 한 바에 따르면,이 구매는 항상 가능해야합니까? 개발자가 자신의 앱을 테스트 할 수 있습니까?

그렇지 않은 경우 상태를 소유하지 않은 상태로 "재설정"할 수 있습니까? Google 인앱 결제 샘플의 util 패키지를 사용하고 있습니다.


소비 요청을 시작하려면이 코드를 스레드에 추가하십시오.

int response = mService.consumePurchase(3, getPackageName(), purchaseToken);

구매 테스트를 위해 여기에 purchaseToken이 있습니다.

purchaseToken = "inapp:" + getPackageName() + ":android.test.purchased";

if (response == 0)

그런 다음 소비가 성공합니다.

mService를 공개하는 것을 잊지 마십시오.

IabHelper.Java

다음과 같이 액세스 할 수 있습니다 :

int response = mHelper.mService.consumePurchase(3, getPackageName(), purchaseToken);

특별한 소비 코드를 작성할 필요가 없습니다. Google Play 스토어 데이터를 지우려면 adb 명령을 사용하십시오.

adb shell pm clear com.android.vending

android.test.purchased 항목은 일반 ID처럼 동작합니다. 다시 구매하려면 코드 어딘가에서 소비해야한다는 의미입니다. Google 문서 가이 문제에 오해의 소지가 있으며 테스트 목적으로 끝없이 살 수있는 또 다른 정적 ID를 추가해야한다고 생각합니다.


인앱 버전 3 :

IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {

    public void onQueryInventoryFinished(IabResult result, Inventory inventory) {

        .....................

        if (inventory.hasPurchase(SKU_CONTENT)) {

            mHelper.consumeAsync(inventory.getPurchase(SKU_CONTENT), null);
        }
    }
};

이것이 아이템을 소비하는 방법입니다

 consume.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    String purchaseToken = "inapp:" + getPackageName() + ":android.test.purchased";
                    try {
                        Log.d("","Running");
                        int response = mService.consumePurchase(3, getPackageName(), purchaseToken);
                        if(response==0)
                        {
                            Log.d("Consumed","Consumed");
                        }else {
                            Log.d("","No"+response);
                        }
                    }catch (RemoteException e)
                    {
                        Log.d("Errorr",""+e);
                    }

                }
            });
            t.start();
        }
    });

버전 3 : Google Play 스토어 캐시를 비우면 "android.test.purchased"를 다시 사용할 수있게됩니다.


나는 adb shell을 사용했다 :

adb shell pm clear com.android.vending

In my opinion if your program is not designed to consume the item you do not need to tweak the code in order to clear the memory of an outside vendor. This will make your code more fragile and you will have then to spend a lot of time to add and remove code that does not belong to your software so it is a bad design to implement a solution like that.

The best solution that worked for me to clear android.test.purchased was

adb uninstall com.yourapp.name

and then

adb shell pm clear com.android.vending

I did not need to clear cash and to browse my apps setting or to change code for that. I did need to add the adb to path variables of windows system which was pretty straight forward. So yes you need to use adb which you probably need anyway so..

You just add your C:\ ...\android-sdk\platform-tools; in windows path in environment variables, and I imagine that it is pretty simple in mac and linux os as well. Hope it helps someone to spend few days less with implementing android in app billings.


The main issue is you have to consume the android.test.purchased item. But this item won't be available in your query inventory, so you can't consume using the normal flow.

So, if you are using IabHelper, in IabHelper class, you can temporarily change the IInAppBillingService mService to public so that it is accessible from your IabHelper.

Then in your class, you can consume like this,

int response = mHelper.mService.consumePurchase(3, getPackageName(), "inapp:"+getPackageName()+":android.test.purchased");

If success, the response is going to be 0.

Hope this helps.


If you are in test environment

1) In the case of android.test.purchased, I can reset the fake payment by restarting android device(consumed the inventory).

2) In InApp util there is a file called Security.java make it as following, for temporary. Since the testing payment(fake) always return false due to security exception.

public static boolean verifyPurchase(String base64PublicKey,
                                     String signedData, String signature) {
    return true; }

Then in your OnIabPurchaseFinishedListener call fechInvForconsumeItem()

IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener
            = new IabHelper.OnIabPurchaseFinishedListener() {
        public void onIabPurchaseFinished(IabResult result,
                                          Purchase purchase)
        {
            if (result.isFailure()) {
                // Handle error
                Log.e("123","Failure");

                return;
            }
            else if (purchase.getSku().equals(ITEM_SKU)) {
                Log.e("123","PURCAsed");
                fechInvForconsumeItem(); // Restart device if not consume

            }

        }
    };

The fechInvForconsumeItem() is

    public void fechInvForconsumeItem() {
    mHelper.queryInventoryAsync(mReceivedInventoryListener);
}
IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener
        = new IabHelper.QueryInventoryFinishedListener() {
    public void onQueryInventoryFinished(IabResult result,
                                         Inventory inventory) {


        if (result.isFailure()) {
            // Handle failure
            Log.e("11","Failure");



        } else {
            Log.e("11","suc");
            mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU),
                    mConsumeFinishedListener);
        }


    }
};

Consume Listener is

    IabHelper.OnConsumeFinishedListener mConsumeFinishedListener =
        new IabHelper.OnConsumeFinishedListener() {
            public void onConsumeFinished(Purchase purchase,
                                          IabResult result) {

                if (result.isSuccess()) {
                } else {
                    // handle error
                    Log.e("11","sucConsume");
                }
            }
        };

For testing purposes I also suggest you to insert a piece of code that will be clearing all the products that you've bought before calling a method that initializes gp purchase flow. That is especially comfortable, when you test just one item at the moment. E.g. like this:

PurchasesResult purchasesResult = mBillingClient.queryPurchases(BillingClient.SkuType.INAPP);
    for (Purchase sourcePurchase : purchasesResult.getPurchasesList()) {
        if(sourcePurchase != null){

            ConsumeResponseListener listener = new ConsumeResponseListener() {
                @Override
                public void onConsumeResponse(String outToken, @BillingResponse int responseCode) {

                    System.out.println("all consumed");
                }
            };
            mBillingClient.consumeAsync(sourcePurchase.getPurchaseToken(), listener);
        }else{
            System.out.println("null");
        }
    }

// and then initiate whole process with clear "shoping basket"

BillingFlowParams.Builder builder = new BillingFlowParams.Builder()
        .setSku(itemName).setType(BillingClient.SkuType.INAPP);

go to Google Play console and open Order Management tab. There you can refund / cancel test purchases.


IabHelper.QueryInventoryFinishedListener 
       mQueryFinishedListener = new IabHelper.QueryInventoryFinishedListener() {
       public void onQueryInventoryFinished(IabResult result, Inventory inventory)   
       {
          if (result.isFailure()) {
             return;
           }          
          try {

                if(inventory.hasPurchase("product_sku_id"))
                {   
                     isItemEnable= true;
                     mHelper.consumeAsync(inventory.getPurchase("product_sku_id"),null);            
                }
                else
                {
                       isItemEnable = false;
                }           

            } catch (Exception e) {
                e.printStackTrace();
            }
       }

    };

In my case, it appears that Google does not record a purchase for the item. Rather, the local copy of Google Play Services caches the purchase. That way, when a second request is made on the same device, android.test.purchased already owned appears. However, using another device or resetting the device clears the cache, and allows the purchase to be repeated.


In my case, I just needed to clear the apps cache. After clearing the cache, I was able to initiate the purchase flow again.

From my device (4.4.2), I navigated to "Settings->Application manager". Next, I selected the app from the "DOWNLOADED" tab, and then "Clear cache".


This is the difference between consumable and non-consumable items; non-consumable items (what you seem to be dealing with here) have their state tracked persistently, while consumable items can be purchased multiple times. You'll have to go into your Play management console and cancel/refund the sale to test it again.

참고URL : https://stackoverflow.com/questions/13896666/in-app-billing-test-android-test-purchased-already-owned

반응형