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)中获得响应,并在获得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月,谷歌自己解决了这个问题。

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

这是因为你没有适当地添加消费侦听器,首先让我们知道为什么需要消费完成侦听器(和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);
            }
        });

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

查询库存完成监听器

// 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 listener

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

编辑

还要确保你也遵循了这些链接,

Link1,Link2

最新更新