【google play】使用Java接入谷歌支付流程
- 整体流程
- 准备工作
- Java实现
整体流程
- 客户端向Java服务端发起支付,生成预订单,将生成的订单号返回给客户端;
- 客户端向Google发起支付(传入本地服务器生成的订单号);
- Google服务器将支付结果返回给客户端;
- 客户端向Java服务端发送支付结果以及订单号,服务端首先进行验签,通过后更新订单状态以及支付信息。
准备工作
- 应用包名(package_name)
- 密钥文件
密钥内部结构:
{"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实现
- 引入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>
- 创建google支付验签用的密钥文件,可以放在Resources下。
- 创建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;}}
}
- 业务逻辑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;}}
- 参数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;
}