Google Play 结算系统是一项可以在Android应用中销售数字产品和内容的服务。
Google Play结算系统销售的数字内容内容分两种:

  • 一次性商品是指用户可以通过一次性的非定期付费(通过用户的付款方式收取)购买的内容。例如额外的游戏关卡、高级战利品箱和媒体文件等等。Google Play管理中心将一次性商品称为“受管理的商品”,而Google Play结算库将其称为“INAPP”商品。一次性商品可以是消耗型商品,也可以是非消耗型商品:

    • 消耗型商品是指用户为了获得应用内内容(如游戏代币)而消耗的商品。当用户消耗该商品时,应用会分配关联的内容,此时购买的商品将不能继续使用。消耗型商品可以购买多次
    • 非消耗型商品是指购买一次就能永久使用的商品。购买后,此类商品会与用户的 Google 帐号永久关联。例如付费升级和关卡包等等
  • 订阅:订阅是一种让用户定期使用内容的商品。订阅期结束后,订阅会自动续订,并且会通过用户的付款方式向用户另行收取费用。订阅会无限期续订,直到被取消。例如在线杂志浏览和音乐在线播放服务等等都属于订阅范畴。Google Play结算库将订阅称为“SUBS”。

购买令牌和订单ID

Google Play使用购买令牌和订单ID跟踪商品和交易。

  • 购买令牌是一个字符串,表示买家对Google Play上的商品的权利。它表明Google用户有权使用由SKU表示的特定商品。可以将购买令牌与Google Play Developer API一起使用。
  • 订单ID是一个字符串,表示Google Play上的财务交易。此字符串会包含在通过电子邮件发送给买家的收据中。可以在销售和付款报告中使用订单ID来管理退款。

每当发生财务交易时,系统都会创建订单ID。只有当用户完成购买流程时,系统才会生成购买令牌。

  • 对于一次性商品,每次购买交易都会创建一个新的购买令牌。大多数购买交易还会生成一个新的订单ID。但是如果不向用户收取任何费用时就不会生成新的订单ID
  • 对于订阅,首次购买交易会创建一个购买令牌和一个订单ID。对于每个连续的结算周期,购买令牌将保持不变,但系统会发放一个新的订单ID。升级、降级、替换和重新注册都会创建新的购买令牌和订单ID

关于订阅,请注意以下几点:

  • 订阅升级、降级和其他订阅购买流程会生成购买令牌,这些令牌必须替换之前的购买令牌。必须使出现在Google Play Developer API的linkedPurchaseToken字段中的购买令牌无效。
  • 订阅续订的订单ID包含一个额外的整数,它表示具体是第几次续订。例如,初始订阅的订单ID可能是GPA.1234-5678-9012-34567,后续订单ID是GPA.1234-5678-9012-34567…0(第一次续订)、GPA.1234-5678-9012-34567…1(第二次续订),依此类推。

注意:如果用户在购买应用内商品时没有应付款项(如在订阅的免费试订期内),则会生成金额为0的订单ID。例如,当用户取消订阅时,订阅将保持有效状态,直到结算周期结束。如果用户决定重新注册,则其帐号中会有一些余额。在这种情况下,系统会创建一个新的购买令牌,创建一个金额为0的订单ID,并在余额扣完后续订。

依赖

dependencies {def billing_version = "4.0.0"//Java版本implementation "com.android.billingclient:billing:$billing_version"//Kotlin版本,包含了Kotlin扩展程序和协程支持implementation "com.android.billingclient:billing-ktx:$billing_version"
}

开发流程

初始化BillingClient

BillingClient是Google Play结算库与应用的其余部分之间进行通信的主接口。PurchasesUpdatedListener接口可以接收应用中所有购买交易的更新。

private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {@Overridepublic void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {// To be implemented in a later section.}
};private BillingClient billingClient = BillingClient.newBuilder(context).setListener(purchasesUpdatedListener).enablePendingPurchases().build();

与Google Play建立连接

创建BillingClient后,您需要与Google Play建立连接。连接过程是异步进行,连接结果通过BillingClientStateListener回调。在onBillingServiceDisconnected()回调方法中实现失去连接以后的重试逻辑。

billingClient.startConnection(new BillingClientStateListener() {@Overridepublic void onBillingSetupFinished(BillingResult billingResult) {if (billingResult.getResponseCode() ==  BillingResponseCode.OK) {// The BillingClient is ready. You can query purchases here.}}@Overridepublic void onBillingServiceDisconnected() {// Try to restart the connection on the next request to// Google Play by calling the startConnection() method.}
});

注意:强烈建议重写onBillingServiceDisconnected()方法实现重试连接逻辑。确保在执行任何方法时都与BillingClient保持连接。

展示可供购买的商品

调用querySkuDetailsAsync()查询应用内商品SKU详情。调用querySkuDetailsAsync()时,需要SkuDetailsParams对象,用于指定在Google Play管理中心创建的商品ID字符串的列表以及SkuType。SkuType可以是SkuType.INAPP(针对一次性商品),也可以是SkuType.SUBS(针对订阅)。

Google Play结算库会将查询结果存储在SkuDetails对象的列表中。然后就可以对该列表中的每个SkuDetails对象调用各种方法,以便查看应用内商品的相关信息,如其价格或说明。

在提供待售商品之前,检查用户是否尚未拥有该商品。如果用户的消耗型商品仍在他们的商品库中,他们必须先消耗掉该商品,然后才能再次购买。

在提供订阅之前,验证用户是否尚未订阅。

List<String> skuList = new ArrayList<> ();
skuList.add("premium_upgrade");
skuList.add("gas");
SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
params.setSkusList(skuList).setType(SkuType.INAPP);
billingClient.querySkuDetailsAsync(params.build(),new SkuDetailsResponseListener() {@Overridepublic void onSkuDetailsResponse(BillingResult billingResult,List<SkuDetails> skuDetailsList) {// Process the result.}});

注意:有些Android设备安装的可能是旧版Google Play商店应用,不支持订阅等某些商品类型。在应用进入结算流程之前,可以调用isFeatureSupported()以确定设备是否支持要销售的商品。

启动购买流程

从应用的主线程调用launchBillingFlow()方法发起购买请求。此方法接受BillingFlowParams对象的引用,该对象包含通过调用querySkuDetailsAsync()获取的相关SkuDetails对象。使用BillingFlowParams.Builder类创建BillingFlowParams对象。

// An activity reference from which the billing flow will be launched.
Activity activity = ...;// Retrieve a value for "skuDetails" by calling querySkuDetailsAsync().
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder().setSkuDetails(skuDetails).build();
int responseCode = billingClient.launchBillingFlow(activity, billingFlowParams).getResponseCode();// Handle the result.

Google Play会将购买操作的结果传送给PurchasesUpdatedListener接口的onPurchasesUpdated()方法中。

@Override
void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {if (billingResult.getResponseCode() == BillingResponseCode.OK&& purchases != null) {for (Purchase purchase : purchases) {handlePurchase(purchase);}} else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) {// Handle an error caused by a user cancelling the purchase flow.} else {// Handle any other error codes.}
}

购买商品成功以后,系统还会生成购买令牌,它是一个唯一标识符,表示用户及其所购应用内商品的商品ID。应用可以在本地存储购买令牌,不过建议将令牌放到后端服务器,可以在服务器上验证购买交易及防范欺诈行为。

处理购买交易

应按以下方式处理购买交易:

  1. 验证购买交易。检查购买交易的状态是否为PURCHASED
  2. 向用户提供内容,并确认内容已传送给用户。还可以选择性地将商品标记为已消费,以便用户可以再次购买商品

注意:如果在三天内未确认购买交易,用户会自动收到退款,并且Google Play会撤消该购买交易

授予用户权利并确认购买交易的流程取决于购买的是非消耗型商品、消耗型商品,还是订阅。

  • 对于消耗型商品,调用consumeAsync()方法确认购买交易并且表明应用已授予用户权利。此外,通过此方法,应用可让一次性商品可供再次购买
void handlePurchase(Purchase purchase) {// Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.Purchase purchase = ...;// Verify the purchase.// Ensure entitlement was not already granted for this purchaseToken.// Grant entitlement to the user.ConsumeParams consumeParams =ConsumeParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build();ConsumeResponseListener listener = new ConsumeResponseListener() {@Overridepublic void onConsumeResponse(BillingResult billingResult, String purchaseToken) {if (billingResult.getResponseCode() == BillingResponseCode.OK) {// Handle the success of the consume operation.}}};billingClient.consumeAsync(consumeParams, listener);
}
  • 对于非消耗型商品,调用BillingClient.acknowledgePurchase()方法或Google Play Developer API中的Product.Purchases.Acknowledge确认购买交易。在确认购买交易之前,应使用Google Play结算库中的isAcknowledged()方法或Google Play Developer API中的 acknowledgementState字段检查该购买交易是否已经过确认。
BillingClient client = ...
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ...void handlePurchase(Purchase purchase) {if (purchase.getPurchaseState() == PurchaseState.PURCHASED) {if (!purchase.isAcknowledged()) {AcknowledgePurchaseParams acknowledgePurchaseParams =AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()).build();client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);}}
}
  • 订阅的确认方式与非消耗型商品类似。可以使用Google Play结算库中的BillingClient.acknowledgePurchase()或Google Play Developer API中的Purchases.Subscriptions.Acknowledge确认订阅。所有初始订阅购买交易都需要确认。订阅续订不需要确认。

查询购买交易

使用PurchasesUpdatedListener监听购买交易更新不足以确保应用会处理所有购买交易。有时应用可能不知道用户进行的部分购买交易。在下面这几种情况下,应用可能会跟踪不到或不知道购买交易:

  • 在购买过程中出现网络问题:用户成功购买了商品并收到了Google的确认消息,但设备在通过PurchasesUpdatedListener收到购买交易的通知之前失去了网络连接
  • 多台设备:用户在一台设备上购买了一件商品,然后在切换设备时想看到该商品
  • 处理应用外进行的购买交易:某些购买交易(如促销活动兑换)可能会在应用外进行

为了处理这些情况,请在onResume()和onCreate()方法中调用BillingClient.queryPurchasesAsync()方法,以确保所有购买交易都得到成功处理。

处理应用外进行的购买交易

某些购买交易(如促销活动兑换)可能发生在应用外。当用户在应用外进行购买交易时,需要显示应用内消息,或使用某种通知机制告知用户应用已正确接收并处理该购买交易。下面是一些可接受的机制:

  • 显示应用内弹出式消息
  • 将消息传送到应用内消息箱,并清楚地指出应用内消息箱中有新消息
  • 使用操作系统通知消息

请注意,当应用识别出购买交易时,有可能处于任何状态。甚至有可能在用户进行购买交易时根本没有安装应用。无论应用处于什么状态,用户都希望在继续使用应用时收到其所购商品。

无论用户进行购买交易时应用处于什么状态,都必须检测购买交易。在一些例外情况下,可以不立即通知用户已收到商品。例如:

  • 当用户在玩游戏时,显示消息可能会让用户分心。在这种情况下,必须待游戏结束后再通知用户
  • 在出现过场动画时,显示消息可能会让用户分心。在这种情况下,必须待过场动画结束后再通知用户
  • 当用户在游戏中学习初始教程和进行用户设置时。建议在新用户打开游戏后立即将奖励通知用户,或在用户进行初始设置期间通知他们。不过,也可以等到用户正式进入游戏环节时再通知用户

待处理的交易

Google Play支持待处理的交易,即从用户发起购买交易到购买交易的付款方式得到处理期间需要执行一个或多个额外步骤的交易。在 Google通知已通过用户的付款方式成功扣款之前,应用不得授予对这些类型的购买交易的权利。

例如,用户可以选择现金作为付款方式来创建应用内商品的PENDING购买交易。然后,用户可以选择在一家实体店完成交易,并通过通知和电子邮件收到一个代码。当用户到达实体店时,他们可以在收银员处兑换该代码并用现金支付。Google随后会通知已收到现金。应用随后就可以授予用户权利了。

在初始化应用的过程中,应用必须通过调用enablePendingPurchases()来支持待处理的交易。

当应用通过PurchasesUpdatedListener或由于调用queryPurchasesAsync()而收到新的购买交易时,使用getPurchaseState()方法确定购买交易的状态是PURCHASED还是PENDING状态。

注意:只有在状态为PURCHASED时,才能授予权利。请使用getPurchaseState()(而非getOriginaljson()),并确保正确处理PENDING 交易

如果应用在用户完成购买交易时正在运行,系统会再次调用PurchasesUpdatedListener接口,并且PurchaseState 现在为PURCHASED状态。此时,应用可以使用处理一次性购买的标准方法处理购买交易。此外,应用还应在其onResume()和onCreate()方法中调用queryPurchasesAsync()方法,以处理应用在未运行时转换到PURCHASED状态的购买交易。

注意:只有状态为PURCHASED时,才能确认购买交易;即在购买交易处在PENDING状态时,请勿确认该交易。当购买交易状态从“PENDING”转换为“PURCHASED”时,3 天的确认期限才会开始

应用还可以通过监听OneTimeProductNotifications,将实时开发者通知与待处理的购买交易一起使用。当购买交易从PENDING过渡到PURCHASED时,应用会收到ONE_TIME_PRODUCT_PURCHASED通知。如果购买交易被取消,应用会收到ONE_TIME_PRODUCT_CANCELED通知。如果客户没有在规定的时间范围内完成付款,就会发生这种情况。当收到这些通知时,可以使用Google Play Developer API,该API包含Purchases.products的PENDING状态。

处理多件商品购买

Google Play允许客户在一笔交易中购买多件相同的应用内商品,只需在购物车中指定商品数量即可(4.0 及更高版本的Google Play结算库支持该功能)。应用应根据指定购买数量来处理多件购买并授予权利。

注意:多件购买适用于消耗型应用内商品,即可以购买、消耗及再次购买的产品。请勿为不支持重复购买的商品启用该功能

为了实现多件购买,应用的配置逻辑需要检查商品数量。可以从以下API访问quantity字段:

  • Play 结算库中的getQuantity()
  • Google Play Developer API中的Purchases.products.quantity

添加用于处理多件商品购买的逻辑后,需要在Google Play管理中心的应用内商品管理页面上为相应的商品启用多件购买功能。

注意:请确保应用接受多件购买,然后再在Google Play管理中心启用该功能。可能需要强制更新到提供支持的应用版本,然后才能在SKU上启用该功能

流程图

谷歌官方示例

感谢大家的支持,如有错误请指正,如需转载请标明原文出处!

Google Play结算服务开发相关推荐

  1. Facebook加入AI芯片大战,挖走Google芯片产品开发负责人

    据外媒 The Information 报道,Facebook 正在投入更多资源用于开发 AI 芯片,并在本月挖走 Google 高级工程师主管 Shahriar Rabii,此前这位主管曾是 Goo ...

  2. Google Map API 开发基础--01

    本章内容将针对如何使用Google Maps API中各个接口进行详细阐述,将采用实例加详解的方式,介绍Google Maps每个类的实际用途和一些WebGIS的开发技巧.在阅读完本章之后,我们希望开 ...

  3. 如何在Android手机上进行Google Map的开发。

    1.题记 提起谷歌Map相信大家都不会陌生,那进入我们今天的话题,如何在Android手机上进行Google Map的开发. 2.Map应用程序的开发 2.1 准备工作 2.1.1 申请Android ...

  4. Web开发与设计之Google兵器谱-Web开发与设计利器

    Google 的使命是 Web,在 Google 眼中,未来的一切应用都将 Web 化,一直以来,Google 为 Web 开发与设计者推出了大量免费工具,让他们更好地创建,维护,改善他们的 Web ...

  5. 谷歌google自动打开开发调式工具问题DevTools

    谷歌google自动打开开发调式工具问题DevTools

  6. Android 平台最新资讯(《Google android 入门开发与实战》pdf完整下载)

    推荐最新学习Android平台网址:[url]http://www.eoeandroid.com[/url] 最新学习<Google android 入门开发与实战>: [url]http ...

  7. Google Android SDK开发范例大全

    1. 图书信息: Google Android SDK开发范例大全(第2版)     人民邮电出版社 2010-6-1 0:00:00 余志龙;陈昱勋;郑名杰;陈小凤;郭秩均 79 元 ISBN:97 ...

  8. Google Web App开发指南

    http://www.html5rocks.com/webappfieldguide/case-studies/case-study-intro/ 第一章:什么是Web Apps? 很多人向我问起学习 ...

  9. 谈谈ali与Google的Java开发规范

    无规矩不成方圆,编码规范就如同协议,有了Http.TCP等各种协议,计算机之间才能有效地通信,同样的,有了一致的编码规范,程序员之间才能有效地合作.道理大家都懂,可现实中的我们,经常一边吐槽别人的代码 ...

最新文章

  1. wordpress本地mysql_如何在本地搭建和运行wordpress
  2. 去年黑客用的未知软件漏洞数量增长一倍 创下纪录
  3. mybatis 传入id_想深入理解MyBatis架构及原理实例分析 把握这些就够了
  4. Server Hard drive mode
  5. 内容自适应编码中的不同粒度
  6. 三菱d700变频器模拟量控制_三菱Q系列PLC,用CCLink控制变频器正反转和多段速
  7. Zigbee 学习计划——第4天——基于CC2530 Basic RF的无线点灯
  8. springboot的一些小问题
  9. c语言投票程序设计报告书,C语言程序设计报告书
  10. STM32官方封装库下载方法
  11. 2019上半年勒索病毒专题报告
  12. 家庭亲戚关系计算器微信小程序源码
  13. walking与Matlab入门教程-控制walking机器人移动
  14. 手写java_JAVA实现简单手写识别
  15. 施乐3030工程机驱动安装
  16. vmstat命令详解!看了很多vmstat的详解,自己总结的
  17. 【转】Endnote中英文混排及输出作者全名的解决办法
  18. FPGA基本功之边沿检测
  19. 【ESP32 乐鑫 离线环境搭建】
  20. EasyConnect服务器启动失败,建议关闭浏览器后重新登录

热门文章

  1. ajax纯js封装函数
  2. python里zip函数使用_Python中zip函数如何使用
  3. 会计常用的智能财税软件是什么?
  4. Graphics类绘制图形
  5. android手机苹果耳机,苹果手机自带耳机相当于什么级别?答案让很多安卓手机“尴尬”!...
  6. outlook 发邮件时换行符号如何设置
  7. oracle cd2500,写入 CD 和 DVD 数据及音频 CD
  8. Google Maps地图查询系统
  9. (附源码)spring boot医院门诊挂号系统 毕业设计 033123
  10. SQL2012清除数据库日志