自学内容网 自学内容网

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

【google play】使用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 包装 credentials
        HttpRequestInitializer 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实现类
@Override
    public 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;
}

原文地址:https://blog.csdn.net/qq_37896194/article/details/143509273

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!