google应用内购(in app billing),点击购买无响应

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了google应用内购(in app billing),点击购买无响应相关的知识,希望对你有一定的参考价值。

参考技术A 在部分手机上,例如小米
集成google的in app billing时,点击购买(或者说调起launchBillingFlow方法)无响应,会打印如下日志:
BillingHelper: Got null intent!
BillingClient: Unexpected null bundle received!

这是因为GooglePlay商店的 【后台弹出界面】的权限关闭了,打开即可

Android支付接入之Google In-app-Billing

 因为公司需要接入Google的应用内支付(即Google的in-app Billing V3),接入过程中查阅了很多的文章,也遇到很多的问题。故此想和大家分享及交流一下心得,好了废话不多说了下面我们开始接入google的应用内支付。

第一步:准备工作

首先想要使用google的支付,首先必须要有一部安装了google play服务的测试机,在这里提供了三个方法:

1)如果有小米的测试机最好因为小米的系统完整的保留了google play服务.

2)如果没有可以看下此处附上的连接:http://zhidao.baidu.com/link?url=qDozAoR_-mlZrVAp6oxLdcyR6uscgdDTsN2Z8PWvdLVF1USqKuAEIjw_QI_9eA5tKbZWIfvhMDhVhLEPjd5AEq 安装Google play的服务.

3)如果以上两种方式你都失败了,不要沮丧下面这种方法可能会更好,点击链接:http://www.droid4x.cn/ 下载海马玩模拟器,它可以一步解决问题。

Google play服务安装完成后如下图所示:

其次你还需要一个VPN账号(美国的最好),推荐一下我使用的VPN(如下图)可以随心所欲的选择地点。

        

最后需要下载开发包,打开Android SDK Manager下载Android SDK的extras部分(如下图),其中有我们支付所用到的包,开发用到的说明文档,例子等等。

下载完成后在SDK目录下可以找到这个文件夹android-sdk-windows\\extras\\google\\play_billing

其中samples是google支付接入的demo,可以根据例子进行google支付的接入。同时在SDK目录下可以找到这个文件夹android-sdk-windows\\docs\\google\\play\\billing这个是google支付的官方说明文档可以对支付工程及原理有一个了解。

说明文档里讲的很详细,建议把文档完整的看一遍,相信如果你看懂了这几个文档,google支付也就很容易搞定了

第二步:代码接入

准备工作做完了,接下来就是代码接入过程了,首先你需要将之前下载的IInAppBillingService.aidl文件添加到你的工程中,添加方法就是在你的工程里新建一个com.android.vending.billing文件夹,将IInAppBillingService.aidl这个 文件拷贝到其中刷新工程即可(具体的可以参考下载的demo)。

其次把之前下载的google支付库中的demo simple例子中的代码粘贴到你的工程文件中(如下图),可以新建一个包放到里面。

在这里说明一下,如果你是和我一样的初学者,可以打着拿来主义的旗号直接使用,但要注意修改一下类名和变量名,毕竟这个代码是公开的大家都可以看到;如果你是大神觉得这个代码写的太low了,也可以自己修改成你想要的那个范。

1.添加权限

接入之前需要在AndroidManifest.xml 文件中添加支付的权限:

<uses-permission android:name="com.android.vending.BILLING" />
2.初始化 IabHelper:

// Create the helper, passing it our context and the public key to verify signatures with
        Log.d(TAG, "Creating IAB helper.");
        mHelper = new IabHelper(this, base64EncodedPublicKey);

        // enable debug logging (for a production application, you should set this to false).
        mHelper.enableDebugLogging(true);

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

                // Have we been disposed of in the meantime? If so, quit.
                if (mHelper == null) return;

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


3.调用支付接口:

是用来购买商品的方法:

mHelper.launchPurchaseFlow(this, SKU_GAS, RC_REQUEST,
                mPurchaseFinishedListener, payload);
购买方法的回调:

// 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 we were disposed of in the meantime, quit.
            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);
            }
            else if (purchase.getSku().equals(SKU_PREMIUM)) {
                // bought the premium upgrade!
                Log.d(TAG, "Purchase is premium upgrade. Congratulating user.");
                alert("Thank you for upgrading to premium!");
                mIsPremium = true;
                updateUi();
                setWaitScreen(false);
            }
            else if (purchase.getSku().equals(SKU_INFINITE_GAS)) {
                // bought the infinite gas subscription
                Log.d(TAG, "Infinite gas subscription purchased.");
                alert("Thank you for subscribing to infinite gas!");
                mSubscribedToInfiniteGas = true;
                mTank = TANK_MAX;
                updateUi();
                setWaitScreen(false);
            }
        }
    };

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

            // if we were disposed of in the meantime, quit.
            if (mHelper == null) return;

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


4.调用查询接口:

是用来查询你当前购买的的商品

mHelper.queryInventoryAsync(mGotInventoryListener);  
查询方法的回调:

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

            // Have we been disposed of in the meantime? If so, quit.
            if (mHelper == null) return;

            // Is it a failure?
            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().
             */

            // Do we have the premium upgrade?
            Purchase premiumPurchase = inventory.getPurchase(SKU_PREMIUM);
            mIsPremium = (premiumPurchase != null && verifyDeveloperPayload(premiumPurchase));
            Log.d(TAG, "User is " + (mIsPremium ? "PREMIUM" : "NOT PREMIUM"));

            // Do we have the infinite gas plan?
            Purchase infiniteGasPurchase = inventory.getPurchase(SKU_INFINITE_GAS);
            mSubscribedToInfiniteGas = (infiniteGasPurchase != null &&
                    verifyDeveloperPayload(infiniteGasPurchase));
            Log.d(TAG, "User " + (mSubscribedToInfiniteGas ? "HAS" : "DOES NOT HAVE")
                        + " infinite gas subscription.");
            if (mSubscribedToInfiniteGas) mTank = TANK_MAX;

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

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

5.消耗商品

因为我们的内购商品是可以重复购买的,但是每次购买之后需要消耗商品,注意这个消耗的意思不是要使用已经购买的商品,而是消除google对改购买商品施加的一个标记,以表示本次购买已成功,之后才可以进行下一次的购买以避免发生重复购买而产生的多次扣款而商品数目不一致的问题。

mHelper.consumeAsync(purchase, mConsumeFinishedListener);

消耗商品的回调:

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

            // if we were disposed of in the meantime, quit.
            if (mHelper == null) return;

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

6.返回数据方法:

在购买时不要忘记添加下面这个方法,它是用来出来返回的数据。

@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.");
        }
    }
7.退出后销毁IabHelper:

在退出时需要销毁IabHelper:

// We're being destroyed. It's important to dispose of the helper here!
    @Override
    public void onDestroy() {
        super.onDestroy();

        // very important:
        Log.d(TAG, "Destroying helper.");
        if (mHelper != null) {
            mHelper.dispose();
            mHelper = null;
        }
    }
第三步:打包上传

首先你需要有一个google开发者账号,登录到google开发者后台添加一个应用,同时添加商品的相关部分。

其次google的支付可不是写完代码编译下就可以支付的,所以完成代码的部分后就需要将工程打包上传到google开发者后台,打包的过程相信不需要我多说什么了吧,不会的可以看下这个连接:http://jingyan.baidu.com/article/7908e85c8dea30af491ad24f.html,上传到Bate版或者ALPHA版,如果是公司开发那应该会有妹子或者汉子帮你完成这个步骤,如果是自己的话那就。。。呵呵。

google的审核过程还是很快的大约半个小时就出炉了,这个时候还需要添加测试账号在这个文档中详细介绍了如何添加测试账号,当然添加测试账号并不意味着你就可以测试了,在审核结束时在google开发者后台的apk界面有一个测试连接,打开后输入测试的账号成为测试人员,这个时候就可以进行google支付的测试了

第四步:测试中的问题

首先测试账号需要有一个绑定的信用卡而且是VISA信用卡账户,点击支付按钮,如果你已经成为测试人员,但是google提示“需要验证身份,需要登录Google账号”这个问题的话很可能是你的商品id有问题,你可以检查下商品id是否正确后重新测试。

关于如何添加商品id google支付的说明文档中会有详细的说明。

如果测试中遇到“无法购买你想要买的商品”这个提示,那可能是你还未成为测试人员或者你用开发者账号进行测试的原因。

1.当前应用程序不支持购买此商品:确定你手机上装的程序包名和签名和后台上传的一致。p.s.上传后台后APK需要等一段时间才能生效。

2.购买的商品不存在 :确保你代码里的商品名字和后台的一致,如果一致,则可能需要等一两个小时再测试,Google后台的问题。

3.loading了很长时间,最后给你提示未知错误:这个不管它,Google后台的问题,等会再测。

最后国内开发者确保是在vpn下进行测试,有什么疑惑的地方可以和我私聊!!!!

源码下载:https://github.com/guojunhua/GooglePay.git


以上是关于google应用内购(in app billing),点击购买无响应的主要内容,如果未能解决你的问题,请参考以下文章

Google Play内购测试

[iOS]应用内支付(内购)的个人开发过程及坑!

iOS内购流程二(添加产品沙盒账号以及上架流程)

[iOS]应用内支付(内购)的个人开发过程及坑!

Amazon App Tester工具的安装和配置-Amazon内购接入流程以及测试

Amazon App Tester工具的安装和配置-Amazon内购接入流程以及测试