Google Pay调研 In-app Billing

来源:互联网 发布:哈工大大数据集团官网 编辑:程序博客网 时间:2024/05/21 10:32

Google Pay 概念

  • 只能用来销售数字内容,不能销售实体商品
  • 应用一旦被购买,无法进行退款服务
  • Google Play不提供内容交付,开发者需要自行交付在应用内购买的数字内容
  • 一个应用不能购买另一个应用发布的商品

开发备忘

混淆时添加

-keep class com.android.vending.billing.**

清单文件添加com.android.vending.BILLING 权限

配置应用的key,初始化Googlepay的时候使用,key的位置
image

代码编写

  • 谷歌提供的sample中有一个aidl文件和util包下的工具类可以使用,功能已经封装好
  • AIDL文件创建com.android.vending.billing的包将IInAppBillingService.aidl放进去(之后进行编译会在gen对应包名下面生成IInAppBillingService.java)
  • com.android.vending.BILLING 权限添加

此后就可以访问google服务了

  1. 初始化尝试连接google服务,如果连接成功就进行消耗性商品的账单查询是否有没有消耗的商品(防止漏单)
mHelper = new IabHelper(this, GOOGLE_PAY_key);        // 打开log日志        mHelper.enableDebugLogging(AppConfigs.isDebug(this));        Mlog.e("google pay 开始初始化.", mContext);        // // ### Google play连接初始化开始 ### 异步回调        mHelper.startSetup(new OnIabSetupFinishedListener() {            @Override            public void onIabSetupFinished(IabResult result) {                Mlog.e("google pay 初始化完成.", mContext);                // 连接过程中出现问题                if (!result.isSuccess()) {                    //                    Mlog.e("谷歌服务未连接上Problem setting up in-app billing: "                            + result, mContext);                    // add 当未连接上谷歌服务的时候就结束,不然在没有google服务的手机上ondestory()中断服务时会出非法状态异常                    mHelper = null;                    return;                }                // 异步过程,连接过程中就结束                if (mHelper == null)                    return;                // ### Google play连接初始化结束 ###                // 查询消耗商品的拥有 状态                Mlog.e("谷歌服务连接成功!开始查询消耗商品的购买状态", mContext);                try {                    mHelper.queryInventoryAsync(mGotInventoryListener);                } catch (IabAsyncInProgressException e) {                    Mlog.e("查询用户物品清单失败. Another async operation in progress.",                            mContext);                }            }        });
  1. 由于此连接耗费性能,所以需要在合适地方中断链接
@Override    protected void onDestroy() {        super.onDestroy();        // 清除与Google Play的链接服务,释放资源        if (mHelper != null) {            mHelper.disposeWhenFinished();            mHelper = null;        }    }
  1. 进行商品购买 launchPurchaseFlow方法的sku是google console中发布商品的id,extreCode是订单号,如果支付成功此订单号会通过purchase.getDeveloperPayload()返回,和本地服务器的后台确定从而完成商品的交付
    。第三个参数是一个商品完成支付的监听
        if (mHelper == null) {            // 表示google服务未连接上            PublicFunc.showMsg(mContext, getResources().getString(R.string.google_pay_error));            return;        }        String sku_name = null;        if ("50".equals(sku)) {            sku_name = Constant.SKU_kb_50;        }         else if ("5".equals(sku)) {            sku_name = Constant.SKU_kb_5;        }         else if ("100".equals(sku)) {            sku_name = Constant.SKU_kb_100;        }         else if ("200".equals(sku)) {            sku_name = Constant.SKU_kb_200;        }        else if ("500".equals(sku)) {            sku_name = Constant.SKU_kb_500;        }        else if ("1000".equals(sku)) {            sku_name = Constant.SKU_kb_1000;        }        else if ("2000".equals(sku)) {            sku_name = Constant.SKU_kb_2000;        }        if (sku_name != null) {            try {                // 这句触发付款界面,界面跳转完成时回到本应用触发回调的方法                mHelper.launchPurchaseFlow(VoucherCenterActivity.this,                        sku_name, request_google_code,                        mPurchaseFinishedListener, extreCode);            } catch (IabAsyncInProgressException e) {                Mlog.e("唤起谷歌支付页面失败. Another async operation in progress.",                        mContext);            }        }
  1. 3的购买方法会触发startactivityforresult启动Google Play支付页面,所以需要重写onactivityresult来获取付款结果,Google Play的回调结果在3中第三个参数设置的监听中触发,可消耗的商品需要在支付完成时进行“消费”
protected void onActivityResult(int requestCode, int resultCode, Intent data) {        Mlog.e("onActivityResult(" + requestCode + "," + resultCode + ","                + data, mContext);        if (mHelper == null)            return;        if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {            super.onActivityResult(requestCode, resultCode, data);        } else {            Mlog.e("onActivityResult handled by IABUtil.", mContext);        }    };
// 付款完成 从谷歌页面返回的回调    IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {        public void onIabPurchaseFinished(IabResult result, Purchase purchase) {            if (mHelper == null)                return;            if (result.isFailure()) {                Mlog.e("Error purchasing 付款失败或者取消付款: " + result, mContext);                return;            }            Mlog.e("Purchase successful.", mContext);            try {                // 触发消费过程                mHelper.consumeAsync(purchase, mConsumeFinishedListener);            } catch (IabAsyncInProgressException e) {                Mlog.e("Error consuming " + cur_sku                        + ". Another async operation in progress.", mContext);                return;            }        }    };
  1. 4中触发消费流程,消费是一个异步过程也需要一个监听

消耗过程的原因

如果是设置的是可重复商品,当你在成功购买这个商品后是需要主动消耗的,只有消耗成功后才可以再次购买。这样设定,第一,可以避免用户重复下单购买,第二,可以保证每笔消费订单的唯一。有了以上两点就可以很好地处理漏单。 so,上面代码在成功设置billing后,第一个操作就是查询拥有的商品,就是做的漏单处理。因为支付过程其实就是你的应用程序—–>Google Play程序(通过Google Play Service)——>Google服务器——->Google Play程序(通过Google Play Service)——>你的应用程序。这样一个交互过程,还需要网络支持,所以每次支付操作不会保证百分百成功,这样就会产生漏单现象,就是用户付费成功了,但是Google Play在通知你的应用程序支付结果时,因为某些原因断掉了,这样你的程序就不知道支付是否操作成功了,so,只好在下次进游戏时查查有没有已经购买的,但是还没有消耗的商品,有的话就消耗掉,然后再把商品发送给用户。因为这个商品在消耗之前,用户是无法再次购买的,所以单个用户就只会对应单一的漏单,不会有重复的漏单。这些信息都是存到Google服务器上的,直接调代码里的查询代码就可以了。

// 消费完成调用    IabHelper.OnConsumeFinishedListener mConsumeFinishedListener = new IabHelper.OnConsumeFinishedListener() {        public void onConsumeFinished(Purchase purchase, IabResult result) {            Mlog.e("物品消费过程完毕. Purchase: " + purchase + ", result: " + result,                    mContext);            if (mHelper == null)                return;            if (result.isSuccess()) {                Mlog.e("物品消费 successful. Provisioning.", mContext);                // new AlertDialog.Builder(mContext).setMessage("sku:" +                // purchase.getSku() + "dingdanhao"                // +purchase.getDeveloperPayload());                // 上传这两个信息                // TODO 这里应该做充值成功的操作            } else {                Mlog.e("物品消费 Error: " + result, mContext);            }        }    };
  1. 对于可消耗的商品,为了防止漏单,可在初始化链接完成时查询拥有商品的清单,对于未消耗的商品进行消耗(之后才可以再次购买此商品),对应1中查询清单的监听实现
// mHelper.queryInventoryAsync异步查询完成时调用    IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {        @Override        public void onQueryInventoryFinished(IabResult result,                Inventory inventory) {            Mlog.e("查询 物品清单 结束.", mContext);            // Have we been disposed of in the meantime? If so, quit.            if (mHelper == null)                return;            // Is it a failure?            if (result.isFailure()) {                Mlog.e("Failed to query 物品清单: " + result, mContext);                return;            }            Mlog.e("Query 物品清单 was successful.", mContext);            // 查询消耗品的拥有状态            for (String sku : skuList) {                Purchase sku_Purchase = inventory.getPurchase(sku);                if (sku_Purchase != null) {                    Mlog.e("现在存在未消费物品-" + sku + ". Consuming it.", mContext);                    try {                        mHelper.consumeAsync(inventory.getPurchase(sku),                                mConsumeFinishedListener);                    } catch (IabAsyncInProgressException e) {                        Mlog.e("未消费物品消费失败. Another async operation in progress.",                                mContext);                    }                }            }        }    };

消耗性商品APi调用流程

在应用中管理消耗型商品购买
下面是购买消耗型应用内商品的基本流程:
1. 调用 getBuyIntent 启动购买流程。
2. 从 Google Play 接收表明购买是否成功完成的响应 Bundle。
3. 如果购买成功,则通过调用 consumePurchase 消耗购买。
4. 从 Google Play 接收表明消耗是否成功完成的响应代码。
5. 如果消耗成功,则在您的应用中配置商品。

之后,当用户启动或登录到您的应用时,您应检查该用户是否拥有任何尚未消耗的消耗型应用内商品;如果有,请务必消耗并配置这些商品。 如果您在应用中实现消耗型应用内商品,则可以采用下面推荐的应用启动流程:
1. 发送 getPurchases 请求,查询此用户拥有的应用内商品。
2. 如果有任何消耗型应用内商品,请通过调用 consumePurchase 消耗这些商品。 必须执行这步操作,因为应用虽然可能已完成此消耗型商品的购买订单,但在其发送消耗请求之前仍有可能已停止运行或断开连接。
3. 从 Google Play 接收表明消耗是否成功完成的响应代码。
4. 如果消耗成功,则在您的应用中配置商品。

后台需要处理的事情

  1. 在 Google Play Developer Console 上设置和维护商品列表。
  2. 注册测试帐户。

只有商品列在应用的商品列表上,您才可以使用 Google Play 的应用内购买结算功能出售它们

接入过程中遇到的问题

针对alpha版本测试
1. 支付时弹出无法购买商品

  • 确保google console上后台测试版本apk的版本号、包名和测试安装的apk一致,并且经过签名 清单中注册有com.android.vending.BILLING 权限
  • 并且测试账号经过测试链接(alpha版本测试页面生成的一个地址)的注册
    image
  • APP的正式版本处于发布状态
    image
    1. 在手机上进行支付测试登录google账号不能是本应用的开发者账号,否则会在弹出开发者无法购买本商品的提示
    2. 测试需要绑定银行卡才能进行购买,在封闭式alpha测试下不会对账户进行扣款,但是绑定银行卡的时候需要选择账单地址,但是目前google好像不支持中国地区的账单,这样会出现您的交易无法完的提示

正式发布

  • 上传一个集成了in-app billing功能的app的正式版本并发布

  • 配置添加完成应用内商品

完成以上两步 用户就可以下载发布的app并登陆谷歌账户进行支付(手机需要安装有google play 和 google service,如果没有连支付的弹框都不会出现)

参考文章

http://blog.csdn.net/change_from_now/article/details/36668017

google In-app Billing demo

https://developer.android.com/google/play/billing/index.html
https://github.com/googlesamples/android-play-billing

谷歌控制台

https://play.google.com/apps/publish/

原创粉丝点击