安卓集成Google Play支付(谷歌支付)最新版本

2023-05-16

Google Play 支付文档:https://developer.android.com/google/play/billing/integrate

Google Play 支付库已经升级到5.0了,相对之前的版本有不少的变化,现在记录下!

接入Google Play 流程还是和之前一样:

1.去Google console 申请开发者账号  https://play.google.com/console/  

2.创建项目,上传APK

3.去Google console项目后台开始设置商品:点击左侧Products---->In-app products(内购商品)或者Subscription(订阅商品)

 4.等Google Pay Console 后台创建好商品后,客户端和后端就可以开始集成了:

  4.1:将 Google Play 结算库依赖项添加到应用的

dependencies {
    val billing_version = "5.0.0"

    implementation("com.android.billingclient:billing:$billing_version")
}

4.2:初始化支付SDK(也就是初始化BillingClient):支付过程中BillingClient用的比较多,一般项目中只创建一个BillingClient

private BillingClient billingClient = BillingClient.newBuilder(context)
    .setListener(purchasesUpdatedListener)
    .enablePendingPurchases()
    .build();

初始化的时候需要一个:PurchasesUpdatedListener,PurchasesUpdatedListener是监听应用中所有购买交易的更新,这个listener非常重要,当用户购买或者订阅后都会走这个回调

private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
        // To be implemented in a later section.
    }
};

4.3初始化SDK后,需要与 Google Play 建立连接,使用startConnection()方法,startConnection是异步进行,这个时候需要一个BillingClientStateListener进行回调连接的结果,当连接完成会走onBillingSetupFinished()回调,通过返回的billingResult.getResponseCode()去判断是否真正的链接成功,这个code 有下面几个值,这个BillingClientStateListener还有一个Google Play 失去连接的回调,这个时候我们需要实现重试逻辑,就是再次调用startConnection()函数。

    @Retention(RetentionPolicy.SOURCE)
    public @interface BillingResponseCode {
        int SERVICE_TIMEOUT = -3;
        int FEATURE_NOT_SUPPORTED = -2;
        int SERVICE_DISCONNECTED = -1;
        int OK = 0;
        int USER_CANCELED = 1;
        int SERVICE_UNAVAILABLE = 2;
        int BILLING_UNAVAILABLE = 3;
        int ITEM_UNAVAILABLE = 4;
        int DEVELOPER_ERROR = 5;
        int ERROR = 6;
        int ITEM_ALREADY_OWNED = 7;
        int ITEM_NOT_OWNED = 8;
    }
  public void startConnection() {
        mBillingClient.startConnection(new BillingClientStateListener() {
            @Override
            public void onBillingSetupFinished(BillingResult billingResult) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                    // The BillingClient is ready. You can query purchases here.
                    queryProductDetailsParams();
                    queryOldOrder();
                }
            }

            @Override
            public void onBillingServiceDisconnected() {
                // Try to restart the connection on the next request to
                // Google Play by calling the startConnection() method.
            }
        });
    }

 4.4 获取商品

      当startConnection()回调成功时,这个时候我们就可以根据ProductId去Google Play获取具体的商品了,这个时候一般会通过API去自己的Server 获取一个ProductIdList,然后根据后台返回的productId去Google Play 获取商品详情。

查询内购的商品:

  List<String> skuList = new ArrayList<>();
        skuList.add("ProductId01");
        skuList.add("ProductId02");
        skuList.add("ProductId03");
        skuList.add("ProductId04");
        SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder();
        params.setSkusList(skuList).setType(BillingClient.SkuType.INAPP);
        mBillingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() {
            @Override
            public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
                // Process the result.
                Log.i(TAG, "querySkuDetailsAsync 1 onSkuDetailsResponse billingResult.getResponseCode : " + billingResult.getResponseCode() + " skuDetailsList :" + skuDetailsList);
                mInAppSkuDetailsHashMap.clear();
                if (skuDetailsList != null && skuDetailsList.size() > 0) {
                    for (SkuDetails skuDetails : skuDetailsList) {
                        mInAppSkuDetailsHashMap.put(skuDetails.getSku(), skuDetails);
                    }
                }
            }
        });

查询订阅的商品:

 // The BillingClient is ready. You can query purchases here.
        List<String> subscribeSkuList = new ArrayList<>();
        subscribeSkuList.add("Subscribe01");
        subscribeSkuList.add("Subscribe01");
        subscribeSkuList.add("Subscribe01");
        SkuDetailsParams.Builder subscribeParams = SkuDetailsParams.newBuilder();
        subscribeParams.setSkusList(subscribeSkuList).setType(BillingClient.SkuType.SUBS);
        mBillingClient.querySkuDetailsAsync(subscribeParams.build(), new SkuDetailsResponseListener() {
            @Override
            public void onSkuDetailsResponse(BillingResult billingResult, List<SkuDetails> skuDetailsList) {
                // Process the result.
                Log.i(TAG, "querySkuDetailsAsync 2 onSkuDetailsResponse billingResult.getResponseCode : " + billingResult.getResponseCode() + " skuDetailsList :" + skuDetailsList);
                mSubscribeSkuDetailsHashMap.clear();
                if (skuDetailsList != null && skuDetailsList.size() > 0) {
                    for (SkuDetails skuDetails : skuDetailsList) {
                        mSubscribeSkuDetailsHashMap.put(skuDetails.getSku(), skuDetails);
                    }
                }
            }
        });

当商品查询成功后就可以结合Server返回的商品信息给用户展示商品列表了

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

4.5.启动购买流程(开始购买)

   当用户点击某个商品时,从应用发起购买请求,请从应用的主线程调用 launchBillingFlow() 方法。此方法接受对 BillingFlowParams 对象的引用,该对象包含通过调用 queryProductDetailsAsync() 获取的相关 ProductDetails 对象。如需创建 BillingFlowParams 对象,请使用 BillingFlowParams.Builder 类。

购买内购的商品:

    public void buyInAppProduct(SkuDetails skuDetails) {
        if (skuDetails == null) {
            return;
        }
        BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                .setSkuDetails(skuDetails)
                .build();
        mBillingClient.launchBillingFlow(ActivityUtils.getTopActivity(), billingFlowParams).getResponseCode();
    }

购买订阅的商品:

  public void buySubscribeProduct(SkuDetails skuDetails) {
        if (skuDetails == null) {
            return;
        }
        BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
                .setSkuDetails(skuDetails)
                .build();
        mBillingClient.launchBillingFlow(ActivityUtils.getTopActivity(), billingFlowParams).getResponseCode();
    }
// An activity reference from which the billing flow will be launched.
Activity activity = ...;

ImmutableList productDetailsParamsList =
    ImmutableList.of(
        ProductDetailsParams.newBuilder()
             // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
            .setProductDetails(productDetails)
            // to get an offer token, call ProductDetails.getSubscriptionOfferDetails()
            // for a list of offers that are available to the user
            .setOfferToken(selectedOfferToken)
            .build()
    );

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(productDetailsParamsList)
    .build();

// Launch the billing flow
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

4.6购买成功的回调

 在咱们4.2初始化SDK的时候添加了一个PurchasesUpdatedListener,当用户购买成功后Google Play 会调用 onPurchasesUpdated(),我们根据responseCode去区分用户购买成功与否.

如果成功购买商品,系统还会生成一个token,它是一个唯一标识符,表示用户及其所购应用内商品的商品 ID。可以在本地存储token,可以将令牌传递到安全的后端服务器(推荐用该方法)

    private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
        @Override
        public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
            if (billingResult == null) {
                return;
            }
            int responseCode = billingResult.getResponseCode();
            switch (responseCode) {
                case BillingClient.BillingResponseCode.OK:
                    for (Purchase purchase : purchases) {
                        SkuDetails skuDetails = null;
                        String json = purchase.getOriginalJson();
                        if (!TextUtils.isEmpty(json)) {
                            PurchaseData purchaseData = GsonConverter.fromJson(json, PurchaseData.class);
                            if (purchaseData != null) {
                                skuDetails = getSkuDetailsDependProductId(purchaseData.getProductId());
                            }
                        }
                        handlePurchase(purchase, (skuDetails != null && (BillingClient.SkuType.SUBS.equals(skuDetails.getType()))), "onPurchasesUpdated");
                    }
                    break;
                case BillingClient.BillingResponseCode.USER_CANCELED:
                    Log.i(TAG, "purchasesUpdatedListener 3 user cancel ");
                    break;
                default:
                    Log.i(TAG, "purchasesUpdatedListener 4 error  " + responseCode);
                    break;
            }
        }
    };
@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.
    }
}

4.7.处理购买交易(消费订单)

当用户购买成功后,订单必须消费,如果不消费,三天后Google会自动退款,撤销购买交易。
消费内购的商品:

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() {
        @Override
        public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // Handle the success of the consume operation.
            }
        }
    };

    billingClient.consumeAsync(consumeParams, listener);
}

  消费订阅商品:订阅的处理方式与非消耗型商品类似。您可以使用 Google Play 结算库中的 BillingClient.acknowledgePurchase() 或 Google Play Developer API 中的 Purchases.Subscriptions.Acknowledge 确认订阅。所有初始订阅购买交易都需要确认。订阅续订不需要确认

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

4.8 查询历史订单,消费待处理的交易

    public void queryOldOrder() {
        mBillingClient.queryPurchasesAsync(BillingClient.SkuType.INAPP, new PurchasesResponseListener() {
            @Override
            public void onQueryPurchasesResponse(@NonNull BillingResult billingResult, @NonNull List<Purchase> list) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                    onHandlerQueryPurchases(list, false);
                }
            }
        });

        mBillingClient.queryPurchasesAsync(BillingClient.SkuType.SUBS, new PurchasesResponseListener() {
            @Override
            public void onQueryPurchasesResponse(@NonNull BillingResult billingResult, @NonNull List<Purchase> list) {
                if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
                    onHandlerQueryPurchases(list, true);
                }
            }
        });

4.9 处理多件购买交易:

Google Play 允许客户在一笔交易中购买多件相同的应用内商品,只需在购物车中指定商品数量即可(4.0 及更高版本的 Google Play 结算库支持该功能)。应用应根据指定购买数量来处理多件购买并授予权利。注意:多件购买适用于消耗型应用内商品,即可以购买、消耗及再次购买的产品。请勿为不支持重复购买的商品启用该功能。

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

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

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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

安卓集成Google Play支付(谷歌支付)最新版本 的相关文章

随机推荐

  • IntelliJ IDEA中有什么让你相见恨晚的好用插件?

    hello xff0c 大家好 xff0c 我是 Jackpop xff0c 硕士毕业于哈尔滨工业大学 xff0c 曾在华为 阿里等大厂工作 xff0c 如果你对升学 就业 技术提升等有疑惑 xff0c 不妨交个朋友 xff1a 我是Jac
  • Android串口的使用(转载+移植)

    提示 xff1a 文章写完后 xff0c 目录可以自动生成 xff0c 如何生成可参考右边的帮助文档 文章目录 前言一 移植java文件二 移植jni文件总结 前言 最近需要在上层app使用串口 发送指令对底层硬件进行操作 xff0c 因此
  • webstorm 代码格式检测

  • Android NFC基础入门

    说道NFC 是Near Field Communication缩写 xff0c 就是近距离无线通讯技术 NFC采用主动和被动两种通信模式 工作的模式有三种 xff0c 读写标签 xff0c 点对点 xff0c 仿真卡模式 xff0c 今天我
  • 嵌入式系统实践 12 ——基于ARM汇编 Keil5 MSP432 P401R开发板

    物联网实验1 阿里云远程控制小灯 span class token comment span span class token comment span span class token comment MSP432P401 span sp
  • Linux下使用rpm包安装MySQL数据库

    root 64 Hadoop102 df h df 34 34 没有那个文件或目录 df 34 h 34 没有那个文件或目录 root 64 Hadoop102 df h 文件系统 容量 已用 可用 已用 挂载点 dev mapper ce
  • Linux下SSH登录的三种方式

    SSH登录 SSH密钥登录 xff1a SSH默认采用密码登录 xff0c 这种方法有很多缺点 xff0c 简单的密码不安全 xff0c 复杂的密码不容易记忆 xff0c 每次手动输入也很麻烦 密钥登录是更好的解决方案 接下来介绍三种SSH
  • 在失望中重找希望——我的2013年工作总结

    时间过的真的是快 来广州已整整工作了一年啦 从2012年长沙工作离职后 为了我的女朋友 我毅然踏上了南下广州的征途 来到羊城后 很快 xff0c 一个礼拜就找到了现在工作的这家公司 现在回想一下 真觉得当初没有好好斟酌一下 2013年里 x
  • ubuntu root开机自登录 与 ros 节点自启

    1 systemctl命令及开机自启 新建a sh文件 放入 cd etc vim a sh xff01 usr bin env bash bash c 34 source opt ros melodic setup bash amp am
  • (原创)详解Glide图片加载库常用方法

    前言 Glide作为安卓开发常用的图片加载库 xff0c 有许多实用而且强大的功能 xff0c 那么 xff0c 今天就来总结一番 xff0c 这次把比较常见的都写出来 xff0c 但并不是全部哦 在介绍之前 xff0c 先来说说什么是Gl
  • 如何将本地windows文件复制到远程windows服务器

    如何使用windows自带的远程桌面连接程序将文件复制到远程服务器内 运行中输入mstsc xff0c 点击确定 输入服务器的IP和端口 xff0c 点击右下角的选项 然后点击本地资源选项卡 点击详细信息按钮 此时勾选你所要连接到服务器上的
  • 强国的语言与语言强国

    强国的语言与语言强国 作者 xff1a 教育部语言文字信息管理司司长 教育部语言文字应用研究所所长 中国社会科学院研究生 李宇明 理论上语言是一律平等的 xff0c 现实中语言是有强有弱的 语言的强弱与语言所属社团的强弱盛衰呈正相关 古罗马
  • 前端post请求报400错误

    前端post请求报400错误 发布时间 xff1a 2019 06 05 18 28 54 400的错误是由于发送请求参数没有成功 原因 xff1a 参数名称类型没有对上 xff1b 或者参数格式不正确 参数格式不正确 xff0c 解决方法
  • Redis集群及其中间遇到的坑

    Redis集群 集群准备 下载并解压Resis xff1a wget http download redis io releases redis 4 0 0 tar gz进入Redis目录下make amp amp make install
  • springmvc的相关配置文件

    最近自己搭了一个小的spring 43 springmvc 43 mybatis的秒杀相关的小工程 xff0c 下面跟大家分享一下 xff0c 用到的配置文件是怎么配置的 xff0c 供参考 我把相关的说明都放在注释中 xff0c 方便阅读
  • C++实现经典同步问题(生产者消费者、读者写者、哲学家进餐、吸烟者问题)

    一 生产者 消费者问题 环境 xff1a windows 问题描述 xff1a 一组生产者进程和一组消费者进程共享一个初始为空 大小为 的缓冲区 xff0c 只有缓冲区没满时 xff0c 生产者才能把消息放入缓冲区 xff0c 否则必须等待
  • token和cookie的区别

    HTTP协议本身是无状态的 xff0c 所以需要一个标志来对用户身份进行验证 1 cookie 用户登录成功后 xff0c 会在服务器存一个session xff0c 同时发送给客户端一个cookie xff0c 这个cookie里面有唯一
  • 在 Vmware 上使用 VxWorks5.5

    Vmware上使用VxWorks5 5 前言 xff1a 1 创建工程 xff1a 可加载工程 xff1a 可引导工程 xff1a 1 5 虚拟机配置 xff1a 2 运行程序 xff1a 前言 xff1a 因为工作中需要用到vxworks
  • virtualbox使用3-配置网络

    终于到正题了 xff0c 哈哈 xff0c 开始的动机就是把如何配置网络记下来 xff0c 省得下次或者日后又要到处搜 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61
  • 安卓集成Google Play支付(谷歌支付)最新版本

    Google Play 支付文档 xff1a https developer android com google play billing integrate Google Play 支付库已经升级到5 0了 xff0c 相对之前的版本有