2

我有一种游戏类型的应用程序。我经历了很多冲浪,但我没有得到任何满意的解决方案。在这里,用户可以多次购买硬币包。我的代码中有一些问题,所以用户只能购买一次。我已阅读有关消耗性 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) 中获取响应,并在获取 purchasePackage() 响应后生成 consumablePurchase()

@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 的数组并使它们成为消耗品。我在启动活动中编写了代码。打印日志在这里

为什么它一次又一次地给出同样的错误?这是 2013 年 3 月谷歌自己解决的一个错误。

任何建议/意见都可以接受!

4

1 回答 1

3

It's happened because you are not properly added Consume listener, first let's know why it is required consume finish listener(and queryInventoryAsync) called when your item is purchased, and Google play store registered that your item is purchased successfully, so that Google play allow user next time to purchase same product from the same google account.

Make sure you have put all this method properly in your activity:

Start Setup

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

on Activity Result:

@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.");
        }
    }

Query Inventory Finish listener

// 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.");
        }
    };

Consume 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.");
        }
    };

on Purchase finish listener

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

        }
    };

EDIT

also make sure you have followed these links too,

Link1 & Link2

Hope it will help you.

于 2013-06-27T09:11:05.780 回答