Покупка расходных материалов в приложении на Android

У меня есть одно игровое приложение. Я пережил много серфинга, но не нашел удовлетворительного решения. Здесь пользователь может купить пакеты монет более одного раза. У меня есть некоторые проблемы в моем коде, поэтому пользователь может купить только один раз. Я прочитал документацию о расходных материалах IAP (покупка в приложении), но все еще та же проблема. Если я вызываю consumablePurchase (), он дает BILLING_RESPONSE_RESULT_DEVELOPER_ERROR (ResponseCode 5).

Шаги:

1) Позвоните в PurchasePackage ("android.test.iap.500coins")

public void purchasePackage(String product_id) {

    try {

        Log.i(TAG, "product name : " + product_id);
        package_name = product_id;

        Bundle buyIntentBundle = mService
                .getBuyIntent(3, getPackageName(), product_id, "inapp",
                        "C890B68423F8EA57F3ED38C3DCC816D7E389F4Cdc4961C23540dadC866B8CFFC5");
        Log.i(TAG,
                "buy intent response :  "
                        + buyIntentBundle
                                .getInt("BILLING_RESPONSE_RESULT_OK"));
        if (buyIntentBundle.getInt("BILLING_RESPONSE_RESULT_OK") == 0) {
            Log.i(TAG, "buyIntentBundle created");
            PendingIntent pendingIntent = buyIntentBundle
                    .getParcelable("BUY_INTENT");
            Log.i(TAG, "pendingIntent created");
            startIntentSenderForResult(pendingIntent.getIntentSender(),
                    1101, new Intent(), Integer.valueOf(0),
                    Integer.valueOf(0), Integer.valueOf(0));
            Log.i(TAG, "startIntentSenderForResult started");
        } else
            Log.i(TAG, "getBuyIntent response not ok");
    } catch (RemoteException e) {
        // TODO: handle exception
        Log.e(TAG, "RemoteException : " + e.getMessage());
    } catch (Exception e) {
        // TODO: handle exception
        Log.e(TAG, "Error in buyStructure : " + e.getMessage());
    }
}

2) получить ответ в onActivityResult (int requestCode, int resultCode, Intent data) и сделать consumablePurchase () после получения ответа на PurchasePackage ()

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // TODO Auto-generated method stub

    Log.i(TAG, "requestCode : " + requestCode + " :resultCode : "
            + resultCode);
    if (data != null && requestCode == 1101) {

        int responseCode = data.getIntExtra("RESPONSE_CODE", -1);
        String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
        String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");

        Log.i(TAG, "responseCode : " + responseCode);
        if (resultCode == RESULT_OK) {
            try {
                switch (responseCode) {

                case 0:
                    /*new Thread() {
                        @Override
                        public void run() {
                            mHandler.sendEmptyMessage(purchaseStart);
                            StartupSync purchaseSync = new StartupSync(
                                    InAppActivity.this, mHandler);
                            purchaseSync.purchasePackage(package_name);
                            mHandler.sendEmptyMessage(purchaseComplete);
                        }
                    }.start(); */
                    JSONObject jo = new JSONObject(purchaseData);
                    String sku = jo.getString("productId");
                    String purchaseToken = jo.getString("purchaseToken");

                    Log.i(TAG, "You have bought the " + sku
                            + ". Excellent choice,adventurer!");

                    int coins = Integer.parseInt(db.selectSettingsValue("coins"));
                    Log.i(TAG, "coins " + coins);
                    coins = coins + intIncCoins;
                    Log.i(TAG, "coins " + coins);

                    db.updateSettings("coins", coins + "");
                    Toast.makeText(
                            InAppActivity.this,
                            "Thank You !",
                            Toast.LENGTH_SHORT).show();
                    finish();

                    int response =  mService.consumePurchase(3, sku, purchaseToken);
                    Toast.makeText(
                            InAppActivity.this,
                            "Response : " + response ,
                            Toast.LENGTH_LONG).show();

                    break;

                case 1:
                    Log.i(TAG, "BILLING_RESPONSE_RESULT_USER_CANCELED");
                    Toast.makeText(InAppActivity.this,
                            "User pressed back or canceled a dialog",
                            Toast.LENGTH_SHORT).show();
                    break;
                case 3:
                    Log.i(TAG,
                            "BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE");
                    Toast.makeText(
                            InAppActivity.this,
                            "Billing API version is not supported for the type requested",
                            Toast.LENGTH_SHORT).show();
                    break;
                case 4:
                    Log.i(TAG, "BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE");
                    Toast.makeText(
                            InAppActivity.this,
                            "Requested product is not available for purchase",
                            Toast.LENGTH_SHORT).show();
                    break;
                case 5:

                    Log.i(TAG, "BILLING_RESPONSE_RESULT_DEVELOPER_ERROR");
                    Toast.makeText(
                            InAppActivity.this,
                            "Invalid arguments provided to the API. This error can also indicate that the application was not correctly signed or properly set up for In-app Billing in Google Play, or does not have the necessary permissions in its manifest",
                            Toast.LENGTH_SHORT).show();
                    break;
                case 6:

                    Log.i(TAG, "BILLING_RESPONSE_RESULT_ERROR");
                    Toast.makeText(InAppActivity.this,
                            "Fatal error during the API action",
                            Toast.LENGTH_SHORT).show();
                    break;
                case 7:
                    Log.i(TAG, "BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED");
                    Toast.makeText(
                            InAppActivity.this,
                            "Failure to purchase since item is already owned",
                            Toast.LENGTH_SHORT).show();
                                            break;
                case 8:
                    Log.i(TAG, "BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED");
                    Toast.makeText(InAppActivity.this,
                            "Failure to consume since item is not owned",
                            Toast.LENGTH_SHORT).show();
                    break;
                }

            } catch (JSONException e) {
                Log.i(TAG, "Failed to parse purchase data.");
                e.printStackTrace();
            } catch (RemoteException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else if (resultCode == RESULT_CANCELED) {
            Toast.makeText(InAppActivity.this, "Purchase Failded",
                    Toast.LENGTH_SHORT).show();
        }
    } else if (resultCode == RESULT_CANCELED) {
        Toast.makeText(InAppActivity.this, "Purchase Canceled",
                Toast.LENGTH_SHORT).show();
    }
    super.onActivityResult(requestCode, resultCode, data);
}

Даже я попробовал другой способ, например, получить массив всех купленных IAP и сделать их расходными. Я написал код в splash activity. Распечатанный журнал находится здесь.

Почему он снова и снова выдает одну и ту же ошибку? Эта ошибка была решена самим Google в марте 2013 года.

Любые предложения / советы приемлемы!


person Chintan    schedule 20.06.2013    source источник
comment
убедитесь, что именно вы хотите, потому что, насколько мне известно, расходные материалы можно приобрести более одного раза, но, наоборот, нерасходуемые товары можно приобрести только один раз. вы написали в своем вопросе, что хотите приобрести монету один раз в приложении, тогда вам следует использовать продукт Non Consumable.   -  person Maulik    schedule 20.06.2013
comment
проверьте эти ссылки: stackoverflow.com / questions / 10619855 / и stackoverflow.com/questions/11513643/ надеюсь, что это поможет вам.   -  person Maulik    schedule 20.06.2013
comment
@Maulik Вопрос отредактирован   -  person Chintan    schedule 20.06.2013
comment
Мы с @Maulik просмотрели такие ссылки, но есть сомнения. Не могли бы вы проверить мой код? Или мы можем связаться лично, чтобы я мог показать вам весь свой код.   -  person Chintan    schedule 20.06.2013
comment
что я понял из вашего вопроса, вы впервые получили успешно приобретенный товар?   -  person Maulik    schedule 22.06.2013
comment
@Maulik Да! Только с первого раза работает.   -  person Chintan    schedule 27.06.2013
comment
проверьте мой ответ ниже.   -  person Maulik    schedule 27.06.2013


Ответы (1)


Это произошло из-за того, что вы не добавили должным образом прослушиватель Consume, сначала давайте узнаем, почему он необходим прослушиватель завершения (и queryInventoryAsync), вызываемый, когда ваш элемент приобретен, и магазин Google Play зарегистрировал, что ваш элемент приобретен успешно, так что Google Play позволяет пользователю в следующий раз, чтобы купить тот же продукт из той же учетной записи Google.

Убедитесь, что вы правильно применили весь этот метод в своей деятельности:

Начать настройку

// Start setup. This is asynchronous and the specified listener
        // will be called once setup completes.
        Log.d(TAG, "Starting setup.");
        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);
            }
        });

по результату деятельности:

@Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + ","
                + data);

        if (mHelper == null)
        return;

        // Pass on the activity result to the helper for handling
        if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
            // not handled, so handle it ourselves (here's where you'd
            // perform any handling of activity results not related to in-app
            // billing...
            super.onActivityResult(requestCode, resultCode, data);
        } else {
            Log.d(TAG, "onActivityResult handled by IABUtil.");
        }
    }

Прослушиватель завершения инвентаризации запросов

// 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;
            }

            // update UI
            // updateUi();
            // setWaitScreen(false);
            Log.d(TAG, "Initial inventory query finished; enabling main UI.");
        }
    };

Использовать Finish Listerner

// Called when consumption is complete
    IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {
        public void onConsumeFinished(Purchase purchase, IabResult result) {
            Log.d(TAG, "Consumption finished. Purchase: " + purchase
                    + ", result: " + result);

            // We know this is the "gas" sku because it's the only one we
            // consume,
            // so we don't check which sku was consumed. If you have more than
            // one
            // sku, you probably should check...
            if (result.isSuccess()) {
                // successfully consumed, so we apply the effects of the item in
                // our
                // game world's logic, which in our case means filling the gas
                // tank a bit
                Log.d(TAG, "Consumption successful. Provisioning.");
                mTank = mTank == TANK_MAX ? TANK_MAX : mTank + 1;
                // saveData();
                alert("You filled 1/4 tank. Your tank is now "
                        + String.valueOf(mTank) + "/4 full!");
            } else {
                complain("Error while consuming: " + result);
            }
            // updateUi();
            // setWaitScreen(false);
            Log.d(TAG, "End consumption flow.");
        }
    };

слушатель завершения покупки

// 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(mHelper == null)
                         return;

            if (result.isFailure()) {
                complain("Error purchasing: " + result);
                // setWaitScreen(false);
                return;
            }
            if (!verifyDeveloperPayload(purchase)) {
                complain("Error purchasing. Authenticity verification failed.");
                // setWaitScreen(false);
                return;
            }

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

            if (purchase.getSku().equals(SKU_GAS)) {
                // bought 1/4 tank of gas. So consume it.
                Log.d(TAG, "Purchase is gas. Starting gas consumption.");
                mHelper.consumeAsync(purchase, mConsumeFinishedListener);
            }

        }
    };

ИЗМЕНИТЬ

также убедитесь, что вы перешли по этим ссылкам,

Link1 и Ссылка2

Надеюсь, это поможет тебе.

person Maulik    schedule 27.06.2013