android - Android 中的消耗品应用内购买

标签 android in-app-purchase google-play in-app-billing android-billing

我有一种游戏应用程序。我经历了很多冲浪,但我没有得到任何满意的解决方案。在这里,用户可以多次购买硬币包。我的代码中存在一些问题,因此用户只能购买一次。我读过documentation about consumable IAP (在 App Purchase 中)仍然是同样的问题。如果我进行 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 的数组并使它们成为可消费的。我在飞溅 Activity 中编写了代码。打印日志为here .

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

接受任何建议/建议!

最佳答案

发生这种情况是因为您没有正确添加 Consume 监听器,首先让我们知道为什么需要在购买商品时调用 consume finish listener(and queryInventoryAsync),并且 Google play 商店注册您的商品已成功购买,以便 Google play 允许用户下次从同一个谷歌帐户购买同一个产品。

确保您已将所有这些方法正确地放入您的 Activity 中:

开始设置

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

关于 Activity 结果:

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

消费完成监听器

// 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 & Link2

希望对你有所帮助。

关于android - Android 中的消耗品应用内购买,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17206706/

相关文章:

java - 应用程序在 Socket 连接时崩溃

android - 在操作栏列表菜单中使用自定义适配器时出现空指针(使用 compat-v7)

30 天后带有 InApp 的 iOS 应用

android - 我可以在批准的应用程序中启动可执行文件吗?

android - 如何在此 ConstraintLayout 中定位 View

java - 通过客户端触发 Restful 服务器响应

iphone - 自动续订订阅退款政策

ios - 快速恢复购买时崩溃

android - 如何更改Google Play和Android主屏幕上的图标?

android - 在 Google Play 管理中心的哪里可以找到用户的崩溃反馈?