笔记:Google Play应用内购买结算(In-app Billing)的接入

Google Play应用内购买结算(In-app Billing)


最近公司有需求在Google渠道上加入Google支付 ,所以照着Google官方文档,写了一个Dome,同时也写这篇博客记录一下希望可以帮到有需要的人。

官方开发文档链接:https://developer.android.com/google/play/billing/api (需要自备梯子)

注意:In-app Billing Version 2 API 已于 2015 年 1 月关闭。如果您现有的应用内购买结算实现使用的是 API 版本 2 或更低版本,则必须迁移到应用内购买结算版本 3。应用内购买结算只能用于销售数字内容,而不能用于销售实体商品、个人服务或任何需要进行实物交付的商品/服务。 与明码标价的应用不同,在用户购买应用内商品后,系统不会提供退款窗口。

应用内购买结算版本 3 提供以下功能:

  • 您的应用通过简化的 API 发送请求,让用户可以轻松地向 Google Play 请求商品详情并订购应用内商品。 API 可以根据用户对商品的所有权快速恢复商品。
  • API 会在购买完成时将订单信息同步传送至设备。
  • 所有购买都是托管的(也就是说,Google Play 负责跟踪用户对应用内商品的所有权)。 用户无论何时都只能拥有同一应用内商品的一个副本而不能拥有多个副本。
  • 您可以消耗所购商品。消耗后,此商品将切换回未被拥有状态,且可被用户从 Google Play 中再次购买。
  • API 支持订阅。

我按个人开发的理解,解释一下:

1、在应用内的购买一切商品,都是通过在Google Play完成,可以理解成,都是调用Google Play完成商品的购买和消耗,在Google Play都有着一切订单信息的保存。

2、相同ID的商品只能被购买一次,不能重复购买,除非该ID的商品被消耗后,才能被重新购买。

开始记录开发流程:

1、环境配置

这里有一些坑,就是在开发最好使用Google手机进行开发,国产系统手机有些装不了Google服务构架,有些无法调起Google Play付款界面。如何安装Google服务构架,可以尝试使用谷歌安装器,这样它会自动帮你转好整个谷歌全家桶。

需要权限:<uses-permission android:name="com.android.vending.BILLING" />

Android SDK需要下载:

将IInAppBillingService.aidl文件放在app同目录下,这个文件可能谷歌在中文SDK中不提供了,可以通过该链接下载:https://download.csdn.net/download/m0_37605407/10578175

编译后会自动生成一个类

完成以上所有步骤后,就完成项目开发环境的配置,同时你要在有翻墙的网络环境下开发,也要确定手机安装了Google Play开发构架,最好是谷歌亲儿子测试,不然会出现很多吐血的坑。

2、谷歌后台上架商品

在谷歌开发者后台,要有企业开发者账号才可以接入支付功能,上架商品,获得商品ID(该ID很重要,谷歌支付不需要支付key,只需要商品id就可以了),在后台你还需要添加测试账号,让相关的测试人员加入该软件的封闭测试,这里有一点不要忘记,将测试账号加入后,需要将里面的验证网址发给他们,让他们完成验证,这才是真正加入测试组。如果想让他们测试里面的支付功能,要将他们加入许可测试组,如果没有加入许可测试组的话,他们测试购买商品需要对应的金额,接入方法如下:

如果你已经完成以上所有步骤,恭喜你已经成功一半拉,哈哈,因为在这里面我遇到了好几个坑。

3、代码实现

  • 绑定到 InAppBillingService

先建立一个new ServiceConnection()在onServiceConnected(ComponentName name, IBinder service) 中绑定InAppBillingService。

代码如下:

IInAppBillingService.Stub.asInterface(service);
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
serviceIntent.setPackage("com.android.vending");//要明确指定地址,防止被拦截
bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);//需要记得解绑

在回调内拉取用户google play store已经拥有的产品,不过要先判断是否支持in-app billing v3(in-app billing v2已经被抛弃)

mService.isBillingSupported(3, packageName, "inapp");

如果返回为0,说明支持,其他返回值详见最后面的附录。

  • 拉取谷歌账号对应拥有的商品
mService.getPurchases(3, packageName,"inapp", null);

备注:第四个参数为continuationToken:用于在拉取数据,如果一次无法拉取完所有数据,而会在Bundle中"INAPP_CONTINUATION_TOKEN" 返回一串String,在接下来继续拉取时,需要该参数,第一次拉取时不用,写入“null”即可。

返回的Bundle,通过get("RESPONSE_CODE")获得响应代码,返回0为请求成功,其他返回值详见最后面的附录。

通过不同key,获得不同类型StringArrayList(官方例子使用“INAPP_PURCHASE_DATA_LIST”)

“INAPP_PURCHASE_ITEM_LIST” - 包含SKU列表的StringArrayList
“INAPP_PURCHASE_DATA_LIST” - 包含购买信息的StringArrayList
“INAPP_DATA_SIGNATURE_LIST” - 包含签名的StringArrayList购买信息

然后通过循环判断用户拥有的产品有没有我们app的需要的ID产品。

  • 获取特定商品的信息,比如价格,信息。商品id由后台提供,无商品id就无法获取该id商品的信息(该操作需要在新线程中,询问,该方法会访问网络,防止ANR)
ArrayList<String> skuList = new ArrayList<String>();
skuList.add(商品ID);
Bundle querySkus = new Bundle();
querySkus.putStringArrayList("ITEM_ID_LIST", skuList);

"ITEM_ID_LIST"为固定的key

mService.getSkuDetails(3, packageName, ITEM_TYPE_INAPP, querySkus);//询问指定ID商品的信息

查询结果将保存在Bundle中带有键 DETAILS_LIST 的字符串 ArrayList 中。购买信息存储在 JSON 格式的字符串中。

对应key-value如下:

  • 购买商品
mService.getBuyIntent(3, getPackageName(), sku, "inapp", "developerPayload 字符串");

developerPayload 字符串:可以由后台生成,生成唯一订单号。

请求成功后,返回的Bundle中getParcelable("BUY_INTENT"),获得PendingIntent,调用startIntentSenderForResult调起Google Play进行购买,(购买方式可以通过金额购买也可以通过促销码付款),Google Play 会将对您的PendingIntent响应发送至应用的onActivityResult方法。

返回的订单类型(JSON 格式的字符串):

'{
   "orderId":"GPA.1234-5678-9012-34567",//唯一的订单号
   "packageName":"com.example.app",
   "productId":"exampleSku",
   "purchaseTime":1345678900000,
   "purchaseState":0,
   "developerPayload":"bGoa+V7g/yqDXvKRqq+JTFn4uQZbPiQJo4pf9RzJ",
   "purchaseToken":"opaque-token-up-to-1000-characters"//用于消耗该商品的令牌
 }'

这里可以对订单进行RSA验证(在后台进行),返回的Intent中的INAPP_DATA_SIGNATURE包含着已使用开发者私钥签署的购买数据签名的字符串。 数据签名使用 RSASSA-PKCS1-v1_5 模式。

在这里为了确保验证用户拥有该产品可以通过getPurchases()拉取用户已经拥有的产品,进行确认。

此处返回的相应代码如果为:7   说明用户已经拥有该产品。

  • 消耗商品
mService.consumePurchase(3, getPackageName(),purchaseToken);

到这里你已经完成了整个购买流程和消耗流程,代码逻辑和常规的PMS应用商品管理一样,没有什么难点,主要还是因为被墙还有国产手机系统被阉割,导致的开发难度高。

在讲一个应用内促销

使用促销代码有两种方式:在应用内购买商品内使用和在google play使用;

1、应用内购买商品内使用

很容易只是在对话框选择用促销代码付款

2、google play商店内兑换使用

应用需要监听google play的数据库变化

IntentFilter promoFilter = new IntentFilter("com.android.vending.billing.PURCHASES_UPDATED");
registerReceiver(myPromoReceiver, promoFilter);

onReceive() 中调用 getPurchases(),判断用户是否使用对应的促销代码onActivityResult,如果就按照购买商品处理。

关于后台支付校验,可以参考这篇博客:

https://www.cnblogs.com/kevin-zou/p/4533091.html

附录(所有可能的请求的返回代码都是一致):

*所有呼叫都将提供具有以下可能值的响应代码
  * RESULT_OK = 0 - 成功
  * RESULT_USER_CANCELED = 1 - 用户按下或取消了对话框
  * RESULT_SERVICE_UNAVAILABLE = 2 - 网络连接已关闭
  * RESULT_BILLING_UNAVAILABLE = 3 - 请求的类型不支持此结算API版本
  * RESULT_ITEM_UNAVAILABLE = 4 - 无法购买请求的SKU
  * RESULT_DEVELOPER_ERROR = 5 - 提供给API的参数无效
  * RESULT_ERROR = 6 - API操作期间出现致命错误
  * RESULT_ITEM_ALREADY_OWNED = 7 - 由于物品已经拥有,因此无法购买
  * RESULT_ITEM_NOT_OWNED = 8 - 由于项目不属于,因此无法使用

可能今后Google应用会有更加成熟的发展,到时该篇博客有些内容可能会被遗弃,该篇博客希望能成为你很好的开发参考资料,如果其中有错误之处,希望大神指出,转载,请标明出处,谢谢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章