【google play】使用Java接入谷歌支付流程

【google play】使用Java接入谷歌支付流程

  • 整体流程
  • 准备工作
  • Java实现

整体流程

  1. 客户端向Java服务端发起支付,生成预订单,将生成的订单号返回给客户端;
  2. 客户端向Google发起支付(传入本地服务器生成的订单号);
  3. Google服务器将支付结果返回给客户端;
  4. 客户端向Java服务端发送支付结果以及订单号,服务端首先进行验签,通过后更新订单状态以及支付信息。

准备工作

  1. 应用包名(package_name)
    在这里插入图片描述
  2. 密钥文件

密钥内部结构:

{"type": "","project_id": "","private_key_id": "","private_key": "","client_email": "","client_id": "","auth_uri": "","token_uri": "","auth_provider_x509_cert_url": "","client_x509_cert_url": "","universe_domain": ""
}

密钥获取方法:

  • 登录Google Cloud Console
    访问 Google Cloud Console 并使用Google账号登录。

  • 创建项目或选择已有项目
    在Google Cloud Console的顶部导航栏中选择一个项目,或者创建一个新项目(点击项目下拉菜单 -> “新建项目”)。

  • 启用Google Play Android Developer API
    选择项目后,进入“APIs & Services” > “Library”。
    搜索 Google Play Android Developer API并启用它。如果项目中没有这个API,就无法进行Google支付相关的操作。

  • 创建服务账号密钥(用于后台验证)
    在“API和服务” > “凭据”页面,点击 “创建凭据”,选择 服务账号。
    为服务账号命名,并为其分配适当的角色(例如角色:Viewer或者Billing Account User)。
    服务账号创建后,进入它的详情页面,点击 “密钥” > “添加密钥” > “创建新密钥”。
    选择 JSON 格式,系统将自动下载包含Google支付密钥的JSON文件。
    注意:这个JSON文件要妥善保管,不能二次获取。

  • 安全保存密钥
    下载的JSON文件包含敏感的支付密钥信息。请将它保存在安全的地方,并确保在代码库中使用适当的保护措施(如环境变量、加密等)来存储密钥。

  • 测试配置
    在应用中集成密钥后,可以通过沙盒环境测试Google支付功能,确保支付流程正常运行。

Java实现

  1. 引入google的pom依赖
        <!-- google支付--><dependency><groupId>com.google.auth</groupId><artifactId>google-auth-library-oauth2-http</artifactId><version>1.11.0</version></dependency><dependency><groupId>com.google.apis</groupId><artifactId>google-api-services-androidpublisher</artifactId><version>v3-rev142-1.25.0</version></dependency>
  1. 创建google支付验签用的密钥文件,可以放在Resources下。
    在这里插入图片描述
  2. 创建GooglePlayClient类
package com.lensung.sd.api.external.google;import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.androidpublisher.AndroidPublisher;
import com.google.api.services.androidpublisher.AndroidPublisherScopes;
import com.google.api.services.androidpublisher.model.ProductPurchase;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.GeneralSecurityException;
import java.util.Collections;/*** @Description* @ClassName GooglePlayClient* @Author SunHui* @Date 2024/11/4 16:21*/@Slf4j
@Component
public class GooglePlayClient {@Value("${google.play.service-account-key}")private String serviceAccountKeyPath;private AndroidPublisher getPublisherService() throws GeneralSecurityException, IOException {GoogleCredentials credentials = GoogleCredentials.fromStream(Files.newInputStream(Paths.get(serviceAccountKeyPath))).createScoped(Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER));// 使用 HttpCredentialsAdapter 包装 credentialsHttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(credentials);return new AndroidPublisher.Builder(GoogleNetHttpTransport.newTrustedTransport(),JacksonFactory.getDefaultInstance(),requestInitializer).setApplicationName("com.lensung.aiyunhua (unreviewed)").build();}public ProductPurchase getPurchaseProductInfo(String packageName, String productId, String purchaseToken) {try {AndroidPublisher publisher = getPublisherService();AndroidPublisher.Purchases.Products products = publisher.purchases().products();return products.get(packageName, productId, purchaseToken).execute();} catch (Exception e) {log.error("getPurchaseProductInfo error", e);return null;}}
}
  1. 业务逻辑service实现类
@Overridepublic Boolean verifyGooglePayReceipt(AppGooglePayReceiptVerifyParam param) {String purchaseToken = param.getPurchaseToken();String productId = param.getProductId();String orderNo = param.getOrderNo();ProductPurchase productPurchase = googlePlayClient.getPurchaseProductInfo(GooglePlayConstant.PACKAGE_NAME, productId, purchaseToken);if (productPurchase == null) {log.error("[ verify receipt error ] purchaseToken:{}, productId:{}, orderNo:{}", purchaseToken, productId, orderNo);return false;}//0: 购买完成(已支付)。//1: 购买被取消。//2: 购买被退款。 通过检查这个字段,后端可以知道购买是否完成或取消。Integer purchaseState = productPurchase.getPurchaseState();String googlePlayOrderId = productPurchase.getOrderId();LocalDateTime purchaseTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(productPurchase.getPurchaseTimeMillis()), ZoneId.systemDefault());Orders orders = ordersRepository.getByOrderNo(orderNo);if (Objects.isNull(orders)) {log.error("[ verify receipt error ] orderNo:{}", orderNo);return false;}// 验证product_id,看返回的product_id与实际的充值金额是不是一致,防止骗单// ...if (0 == purchaseState) {// 支付成功// 1、更新订单状态// ...// 2、发放权益// ...return true;} else {// 支付失败,打印日志,更新订单信息// ...return false;}}
  1. 参数AppGooglePayReceiptVerifyParam
package com.lensung.sd.api.resource.model.param;import lombok.Data;import javax.validation.constraints.NotNull;/*** @Description* @ClassName AppGooglePayReceiptVerifyParam* @Author SunHui* @Date 2024/11/4 16:41*/
@Data
public class AppGooglePayReceiptVerifyParam {/*** google支付票据*/@NotNull(message = "purchaseToken不能为空")private String purchaseToken;/*** 商品id*/@NotNull(message = "productId不能为空")private String productId;/*** 商家自定义订单号*/@NotNull(message = "orderNo不能为空")private String orderNo;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/465464.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实现GUI界面中的logo图片的编码与隐藏

实现GUI界面中的logo图片的编码与隐藏 一、问题描述二、解决办法 一、问题描述 利用PyQt5编写的GUI界面&#xff0c;有时候需要我们添加自定义的图片来作为UI界面的logo&#xff0c;在源码使用时&#xff0c;logo的形式一般不影响使用&#xff0c;但是当我们需要将软件进行打包…

2024最新的开源博客系统:vue3.x+SpringBoot 3.x 前后端分离

本文转载自&#xff1a;https://fangcaicoding.cn/article/54 大家好&#xff01;我是方才&#xff0c;目前是8人后端研发团队的负责人&#xff0c;拥有6年后端经验&3年团队管理经验&#xff0c;截止目前面试过近200位候选人&#xff0c;主导过单表上10亿、累计上100亿数据…

sqli-labs(第一关)

前言&#xff1a; 各位&#xff0c;我准备最近把靶场练一下&#xff0c;看看别人的payload&#xff0c;跟着别人学一下怎么实战。我用的靶场是sqli-labs。 正文&#xff1a; 第一关&#xff1a; &#xff08;1&#xff09;找注入点&#xff1a; 刚开始界面是这样的&#xf…

LabVIEW气体检测系统

随着工业化进程的加速&#xff0c;环境污染问题愈加严峻&#xff0c;尤其是有害气体的排放对人类生存环境构成了严重威胁。为了更好地监测这些有害气体&#xff0c;开发一个高效、准确且易于操作的气体检测系统显得尤为重要。LabVIEW软件开发的气体检测系统&#xff0c;采用激光…

盘点10款录音转文字工具,帮你开启高效记录。

如果你有课堂录音或者是一些网课内容像转成文字笔记&#xff1b;或者是想将会议录音转换成书面的文稿&#xff1b;又或者是想将访谈音频或者是商务谈判转换成文字稿件&#xff1b;那就千万要收藏这些录音转文字的工具&#xff0c;它们的功能专业&#xff0c;转换准确且效率很高…

IntelliJ IDEA 设置数据库连接全局共享

前言 在日常的软件开发工作中&#xff0c;我们经常会遇到需要在多个项目之间共享同一个数据库连接的情况。默认情况下&#xff0c;IntelliJ IDEA 中的数据库连接配置是针对每个项目单独存储的。这意味着如果你在一个项目中配置了一个数据库连接&#xff0c;那么在另一个项目中…

Memento 备忘录模式

备忘录模式 意图结构适用性实例Java Web开发中的简单示例Originator 类Memento 类Caretaker 类 文本编辑器示例1. Originator (发起人) - TextEditor2. Memento (备忘录) - TextMemento3. Caretaker (负责人) - History4. 使用示例输出 备忘录模式&#xff08;Memento Pattern&…

国际版JAVA同城打车源码同城服务线下结账系统源码适配PAD支持Android+IOS+H5

一、数据中心 总用户数今日接单数量今日新增今日收入本月新增本月收入本年新增本年收入 二、用户中心 全部用户普通用户师傅用户推广员用户 三、财务中心 提现管理收入统计提现统计充值统计充值记录保证金管理平台收入统计 四、首页装修 轮播图分享图语音播报配置 五…

Ubuntu学习笔记 - Day3

文章目录 学习目标&#xff1a;学习内容&#xff1a;学习笔记&#xff1a;vim简介vim键盘图工作模式 vim移动光标操作上下左右移动翻页 vim替换和删除操作替换删除 vim插入模式详解进入模式搜索 vim底行模式操作保存退出行号 学习目标&#xff1a; 一周掌握 Linux基本使用技巧 …

数据结构 - 图

今天我们开始学习目前学习到的最难最复杂的数据结构图。 简单回顾一下之前学习的数据结构&#xff0c;数组、单链表、队列等线性表中数据元素是一对一关系&#xff0c;而树结构中数据元素是一对多关系&#xff0c;而图结构中数据元素则是多对多关系&#xff0c;任何两个数据元素…

java.lang.NoClassDefFoundError: kotlin/jvm/JvmInline

springboot项目&#xff0c;调用接口时&#xff0c;报这个错误&#xff0c;跟踪断点发现数据库也查询到了数据&#xff0c;就是在返回时报错了&#xff0c;后来一看是pom.xml中引入了 <dependency><groupId>com.fasterxml.jackson.module</groupId><artif…

WebAPI编程(第五天,第六天,第七天)

WebAPI编程&#xff08;第五天&#xff0c;第六天&#xff0c;第七天&#xff09; **day05 - Web APIs****1.1. **元素偏移量 offset 系列1.1.1 offset 概述1.1.2 offset 与 style 区别offsetstyle 1.1.3 案例&#xff1a;获取鼠标在盒子内的坐标1.1.4 案例&#xff1a;模态框拖…

xshell连接不上linux的原因

1、首先我们确定好linux的配置&#xff0c;右键选择设置&#xff0c;将网络适配器设置成NAT模式 2、点击linux编辑&#xff0c;选择虚拟网络 打开以后选中自己要配置的服务 3、进入以后选中自己的服务&#xff0c;确保是NAT模式&#xff0c;然后配置好子网ip&#xff08;尽量ip…

进程与线程+多线程优势

区别&#xff1a; 1、进程中包含线程&#xff0c;每一个进程都至少一个线程&#xff08;主线程&#xff09; 2、进程是申请系统资源的最小单位 3、进程是CPU调度的最小单位 4、线程之间共享进程申请的系统资源 5、一个线程崩溃了会影响整个进程 进程的组织方式&#xff1…

Unity3D学习FPS游戏(8)装弹和弹夹UI显示

前言&#xff1a;实现了武器的基本发射功能&#xff0c;但是我们弹夹数量是有限&#xff0c;之前并没有做装弹和弹夹显示的功能。本篇实现装弹和弹夹显示。 装弹和弹夹UI显示 装弹目标思路和实现 弹夹UI显示目标弹夹UI的思路和实现UI代码的思路和实现 武器控制的完整代码效果补…

计算机网络——网络层导论

转发是局部功能——数据平面 路由是全局的功能——控制平面 网卡 网卡&#xff0c;也称为网络适配器&#xff0c;是计算机硬件中的一种设备&#xff0c;主要负责在计算机和网络之间进行数据传输。 一、主要功能 1、数据传输&#xff1a; 发送数据时&#xff0c;网卡将计算机…

6款IntelliJ IDEA插件,让Spring和Java开发如虎添翼

文章目录 1、SonarLint2、JRebel for IntelliJ3、SwaggerHub插件4、Lombok插件5、RestfulTool插件6、 Json2Pojo插件7、结论 对于任何Spring Boot开发者来说&#xff0c;两个首要的目标是最大限度地提高工作效率和确保高质量代码。IntelliJ IDEA 是目前最广泛使用的集成开发环境…

【MySQL】深度学习与解析 : 库的操作知识整合

前言&#xff1a;本节内容是MySQL库的操作&#xff0c; 内容较少&#xff0c; 大体内容为创建库、删除库、修改库、库备份操作。 ps:本节内容适合安装了MySQL的友友们进行观看&#xff0c; 实操更有利于记住哦。 目录 创建数据库 查看数据库列表 创建数据库 删除数据库 …

开源 AI 智能名片 2+1 链动模式 S2B2C 商城小程序与私域流量圈层

摘要&#xff1a;本文探讨了私域流量圈层的特点以及其在当今时代的重要性&#xff0c;分析了开源 AI 智能名片 21 链动模式 S2B2C 商城小程序源码在私域流量圈层构建中的作用&#xff0c;阐述了产品在圈层时代被标签化的现象&#xff0c;并以实例展示了如何利用该小程序源码打造…

第11章 LAMP架构企业实战

Linux下LAMP(Linux+Apache+MySQL/MariaDB+Perl/PHP/Python)是一组用来搭建动态网站的开源软件架构,本身是各自独立的软件服务,放在一起使用,拥有了越来越高的兼容度,共同组成了一个强大的Web应用程序平台。 本章介绍互联网主流企业架构LAMP应用案例、PHP解释性语言详解、…