web-dev-qa-db-ja.com

android:アプリ内課金:エラー応答:7:アイテムは既に所有されています

たとえば、寄付ボタンを押したときに人々が$を寄付できるように、アプリにアプリ内課金を実装することを学んでいます。

ユーザーは複数回寄付することができます。つまり、購入は消耗品です。

以下のコードは、TrivalDriveサンプルとWebからのいくつかのチュートリアルから提供されています。

コード:

_IabHelper mHelper;
static final String ITEM_SKU = "Android.test.purchased"; 

@Override
protected void onCreate(Bundle savedInstanceState) 
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_in_app_billing);

    buy10Button = (Button) findViewById(R.id.buy10Button); 
    buy15Button = (Button) findViewById(R.id.buy15Button); 
    buy20Button = (Button) findViewById(R.id.buy20Button);      

    String base64EncodedPublicKey = "keykeykey";

    mHelper = new IabHelper(this, base64EncodedPublicKey);


    mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() 
    {
          public void onIabSetupFinished(IabResult result) 
          {
            if (!result.isSuccess()) 
            {
               Log.d(TAG, "In-app Billing setup failed: " + result);
               return;
            } 
            if (mHelper == null) 
            {
                return;
            }          
            Log.d(TAG, "In-app Billing is set up OK");
          }
    });     
}

public void buy10Click(View view) 
{
    mHelper.launchPurchaseFlow(this, ITEM_SKU, 10001,  mPurchaseFinishedListener, "");
}

public void buy15Click(View view) 
{

}

public void buy20Click(View view) 
{

}   

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{
    if (mHelper == null) return;  
    if (!mHelper.handleActivityResult(requestCode, resultCode, data)) 
    {     
        super.onActivityResult(requestCode, resultCode, data);
    }
}

IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() 
{
    public void onIabPurchaseFinished(IabResult result, Purchase purchase) 
    {
        if (mHelper == null) return;
        if (result.isFailure()) 
        {
           // Handle error
               return;
        }      
        else if ((purchase.getSku().equals(ITEM_SKU)))   
        {
           consumeItem();
        }              
    }
};

public void consumeItem() 
{
    mHelper.queryInventoryAsync(mReceivedInventoryListener);
}

IabHelper.QueryInventoryFinishedListener mReceivedInventoryListener = new IabHelper.QueryInventoryFinishedListener() 
{
    public void onQueryInventoryFinished(IabResult result, Inventory inventory) 
    {
        if (mHelper == null) return;
        if (result.isFailure()) 
        {
            // Handle failure
        } 
        else 
        {
            mHelper.consumeAsync(inventory.getPurchase(ITEM_SKU), mConsumeFinishedListener);
        }
    }
};

IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() 
{
    public void onConsumeFinished(Purchase purchase, IabResult result) 
    {
        if (mHelper == null) return;
        if (result.isSuccess()) 
        {
            Toast.makeText(InAppBillingActivity.this, "Thank you for your donation!!", Toast.LENGTH_LONG).show();   
        } 
        else 
        {
            // handle error
        }
    }
};
_

質問:

それでもE/IabHelper(13392): In-app billing error: Unable to buy item, Error response: 7:Item Already Ownedエラーを受け取り続け、Google Playの支払いダイアログがポップアップしません。

私は多くの同様の状況を調査し、数分待ってから購入がリセットされることを提案しましたが、購入はそれ自体でリセットされますが、私はほぼ1時間待っていましたが、それでもひどいです。

また、誰かがIabResult public boolean isSuccess() { return mResponse == IabHelper.BILLING_RESPONSE_RESULT_OK; }を変更してisSuccess = trueとして_BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED_も返すように提案することを発見しましたが、そのような修正方法はわかりません...

どのように問題を修正できますか?ありがとう!!

26
pearmak

ここで私の以下のコードを確認してください:

あなたのコードでは、購入完了リスナーでクエリインベントリを使用した理由がわかりません。 ConsumeAsync()メソッドは、要求されたSKUと同じSKUを取得しているときに呼び出す必要があります。

// Callback for when a purchase is finished
    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
        public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
            Log.d(TAG, "Purchase finished: " + result + ", purchase: "
                    + purchase);
            if (result.isFailure()) {
                complain("Error purchasing: " + result);
                return;
            }
            if (!verifyDeveloperPayload(purchase)) {
                complain("Error purchasing. Authenticity verification failed.");
                return;
            }

            Log.d(TAG, "Purchase successful.");

            if (purchase.getSku().equals(SKU_GAS)) {

                 // remove query inventory method from here and put consumeAsync() directly
                mHelper.consumeAsync(purchase, mConsumeFinishedListener);

            }

        }
    };

startSetupメソッド

// startSetupメソッドでクエリインベントリメソッドを呼び出すのを忘れました。

 mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
                public void onIabSetupFinished(IabResult result) {
                    Log.d(TAG, "Setup finished.");

                    if (!result.isSuccess()) {
                        // Oh noes, there was a problem.
                        complain("Problem setting up in-app billing: " + result);
                        return;
                    }

                    // Hooray, IAB is fully set up. Now, let's get an inventory of
                    // stuff we own.
                    Log.d(TAG, "Setup successful. Querying inventory.");
                    mHelper.queryInventoryAsync(mGotInventoryListener);
                }
            });

QueryInventoryFinishedListener

また、要求された条件の購入がnullに等しくなく、クエリインベントリ終了リスナーの開発者ペイロードも同じであるかどうかを確認します。

if (gasPurchase != null && verifyDeveloperPayload(gasPurchase)){
    //code
}
// Listener that's called when we finish querying the items and
        // subscriptions we own
        IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
            public void onQueryInventoryFinished(IabResult result,
                    Inventory inventory) {
                Log.d(TAG, "Query inventory finished.");
                if (result.isFailure()) {
                    complain("Failed to query inventory: " + result);
                    return;
                }

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

                /*
                 * Check for items we own. Notice that for each purchase, we check
                 * the developer payload to see if it's correct! See
                 * verifyDeveloperPayload().
                 */

                // // Check for gas delivery -- if we own gas, we should fill up the
                // tank immediately
                Purchase gasPurchase = inventory.getPurchase(SKU_GAS);
                if (gasPurchase != null && verifyDeveloperPayload(gasPurchase)) {
                    Log.d(TAG, "We have gas. Consuming it.");
                    mHelper.consumeAsync(inventory.getPurchase(SKU_GAS),
                            mConsumeFinishedListener);
                    return;
                }
            }
        };

それが起こった理由の説明:

消耗品アイテムを購入した場合、Google Playストアは管理されません。製品購入の詳細やその他のアイテムはGoogle Playコンソールで管理されます。そのため、consumeAsync()メソッドを呼び出す必要があります。アイテムを購入したとき、Google Playストアはレコードアイテムを1回購入し、2回目の購入を許可します。

それがあなたの問題を解決することを願っています。

20
Maulik

「Android.test.purchased」を購入しましたが、消費しませんでした。ただし、すぐに消費するのを忘れた場合、再度消費するのは簡単ではありません。 14日間待つことができます。偽の購入は自動的にクリアされます。しかし、それは受け入れられません。

私は解決策を見つけるのに多くの時間を費やしました:

この行を追加して、デバッグ情報を取得します。

_iabHelper.enableDebugLogging(true, "TAG");

アプリを実行します。 LogCatでは、次のようなjson文字列が表示されます。

{"packageName":"com.example","orderId":"transactionId.Android.test.purchased","productId":"Android.test.purchased","developerPayload":"123","purchaseTime":0,"purchaseState":0,"purchaseToken":"inapp:com.example:Android.test.purchased"}

手動で使用します(THAT_JSON_STRINGをjson文字列に置き換えます)

    Purchase purchase;
    try {
        purchase = new Purchase("inapp", THAT_JSON_STRING, "");
        _iabHelper.consumeAsync(purchase, new OnConsumeFinishedListener() {

            @Override
            public void onConsumeFinished(Purchase purchase, IabResult result) {
                Log.d("TAG", "Result: " + result);
            }
        });
    } catch (JSONException e) {
        e.printStackTrace();
    }

_iabHelperはmHelperです。

38
Vince Yuan

デバイスを再起動するだけで、「購入を消費する」ことができました。

6
JohnK

Google Playの「財務レポート」->「詳細については、販売アカウントをご覧ください」->「注文」を使用して、「消費」する注文を表示およびキャンセルできます。次に、デバイスを再起動する必要があります。 =)

5
Maksim