0%

springboot接入谷歌支付

撸代码前的准备工作

前阵子公司项目需要用到谷歌支付,开始接触的我懵懂摸索了一星期,终于和安卓对接好了谷歌支付。啥都不说了,直接上图:
1.进入Google Play Console ,https://play.google.com/apps/publish/?account=7344212024493937034#AppListPlace
2.设置->API访问->创建oauth2客户端->关联刚创建的项目


3.可以创建服务账号

4.进入API和服务->设置认证信息和oauth2统一画面

认证信息

oauth2同意画面


5.可以点击项目选择创建oauth2客户端 或者服务帐号

6.下载oauth2客户端json或进入管理账户下载账户的secret.json或p12文件

基本的控制台设置流程就是这了,接下来再看代码部分:

代码部分

1.先在application.yml配置google账号的信息,如下图

注意:服务器谷歌支付验证有两种方式:1请求googleapi验证 2.使用公密钥验证。在这里我使用的是第一种方式请求google api验证,第二种我也写了 但是不怎么好使_,在这里我也附上代码。。。
google配置类GooglePayConfig.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.xy.goone.config.pay;

import com.xy.goone.common.util.pay.GooglePayVerifyUtil;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

/**
* @author fumei.jiang
* @date 2019-09-24 15:15
*/
@Configuration
@ConfigurationProperties(prefix = "app.google.config")
public class GooglePayConfig {

private String keyFile;
private String pkcs;
private String serviceAccountEmail;
private String client_id;
private String client_secret;
private String refresh_token;

public String getKeyFile() {
return keyFile;
}

public void setKeyFile(String keyFile) {
this.keyFile = keyFile;
}

public String getPkcs() {
return pkcs;
}

public void setPkcs(String pkcs) {
this.pkcs = pkcs;
}

public String getServiceAccountEmail() {
return serviceAccountEmail;
}

public void setServiceAccountEmail(String serviceAccountEmail) {
this.serviceAccountEmail = serviceAccountEmail;
}

public String getKeylongString(){
return GooglePayVerifyUtil.load(this.getKeyFile());
}

public String getPkcslongString(){return GooglePayVerifyUtil.load(this.getPkcs());}

public String getClient_id() {
return client_id;
}

public void setClient_id(String client_id) {
this.client_id = client_id;
}

public String getClient_secret() {
return client_secret;
}

public void setClient_secret(String client_secret) {
this.client_secret = client_secret;
}

public String getRefresh_token() {
return refresh_token;
}

public void setRefresh_token(String refresh_token) {
this.refresh_token = refresh_token;
}
}

验证工具类GooglePayVerifyUtil.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package com.xy.goone.common.util.pay;


import org.apache.commons.codec.binary.Base64;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;

/**
* @author fumei.jiang
* @date 2019-08-07 16:14
* 谷歌支付
*/
public class GooglePayVerifyUtil {

/*@Value(value = "${google.p12key}")
private String p12;

@Value(value = "${google.email}")
private String email;

@Value("${google.packageName}")
private String packageName;

public static void main(String[] args) throws Exception {

HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();

PrivateKey privateKey = SecurityUtils.loadPrivateKeyFromKeyStore(
SecurityUtils.getPkcs12KeyStore(),
new FileInputStream(new File("{P12 key file}")), // 生成的P12文件
"notasecret", "privatekey", "notasecret");

GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(transport).setJsonFactory(JacksonFactory.getDefaultInstance())
.setServiceAccountId("{Email address}") // e.g.: 626891557797-frclnjv31rn4ss81ch746g9t6pd3mmej@developer.gserviceaccount.com
.setServiceAccountScopes(AndroidPublisherScopes.all())
.setServiceAccountPrivateKey(privateKey).build();

AndroidPublisher publisher = new AndroidPublisher.Builder(transport,
JacksonFactory.getDefaultInstance(), credential).build();

AndroidPublisher.Purchases.Products products = publisher.purchases().products();

// 参数详细说明: https://developers.google.com/android-publisher/api-ref/purchases/products/get
AndroidPublisher.Purchases.Products.Get product = products.get("{packageName}",
"{productId}", "{token}");

// 获取订单信息
// 返回信息说明: https://developers.google.com/android-publisher/api-ref/purchases/products
// 通过consumptionState, purchaseState可以判断订单的状态
ProductPurchase purchase = product.execute();
}
*/

public static boolean docheck(String content, String sign, String publicKey) throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.decodeBase64(publicKey);
PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes("utf-8"));
return signature.verify(Base64.decodeBase64(sign));
}


public static String PRIVATE_KEYS;
public static synchronized String load(String file) {
if (PRIVATE_KEYS == null) {
if (!file.startsWith("/")) {
file = GooglePayVerifyUtil.class.getResource("/").getFile() + File.separator + file;
}
File f = new File(file);
try (InputStreamReader reader = new InputStreamReader(new FileInputStream(f), "utf8");) {
StringBuffer buffer = new StringBuffer();
char[] bf = new char[1024];
while (true) {
int size = reader.read(bf);
if (size < 0)
break;
buffer.append(bf, 0, size);
}
PRIVATE_KEYS = buffer.toString();
} catch (IOException e) {
throw new RuntimeException("read file error ! " + f.getAbsolutePath(), e);
}
}
return PRIVATE_KEYS;
}


}

OrderController.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
 private static Map<String, String> cacheToken = null;//设置静态变量,用于判断access_token是否过期
@Authorization
@PostMapping(value = "/createOrder")
@ApiOperation(value = "创建本地订单")
public Result<Object> createOrder(@RequestBody Order order, @CurrentUser User user) {
Order sysOrder = new Order();
sysOrder.setQuantity(order.getQuantity());
sysOrder.setPayType(order.getPayType());
sysOrder.setMoney(order.getMoney());
sysOrder.setType(order.getType());
sysOrder.setUser(user);
sysOrder.setStatus(Constant.PAY_FAILURE);
String no = String.valueOf(System.currentTimeMillis());//订单号
sysOrder.setNo(no + RandomUtil.getRandomNum());//时间戳+随机六位数
orderRepository.save(sysOrder);
return new ResultUtil<>().setData(sysOrder.getNo());
}


@RequestMapping(value = "/googlePayVerify", method = RequestMethod.POST)
@ApiOperation(value = "谷歌支付方式二:通过请求谷歌api验证")
@Authorization
public Result<Object> googlePlayVerify(@RequestBody Pay.Payment payment, @CurrentUser User user) {
String no = payment.getNo();
int type = payment.getType();//类型:0 消耗 1购买
Pay.Purchase receipt = payment.getPurchase();
//先校对与本地订单
Order localOrder = orderRepository.findByNo(no);//禁止重复刷单
if (localOrder == null) {
return new ResultUtil<>().setErrorMsg(this.i18n("order.does.not.exist.and.recharge.failed"));
}
if (localOrder.getStatus() == Constant.PAY_SUCCESS) {
return new ResultUtil<>().setErrorMsg(this.i18n("this.order.has.been.successfully.recharged.and.cannot.be.refilled"));
}

JSONObject jsonObject = null;
try {
String json = JsonUtil.objectToJson(receipt);
jsonObject = JSON.parseObject(json);
} catch (JSONException e) {
throw new HttpRequestException(HttpServletResponse.SC_NOT_ACCEPTABLE, this.i18n("data.parsing.failed"));//数据解析失败
}
if (null != cacheToken) {
Long expires_in = Long.valueOf(cacheToken.get("expires_in")); // 有效时长
Long create_time = Long.valueOf(cacheToken.get("create_time")); // access_token的创建时间
Long now_time = (new Date().getTime()) / 1000;
if (now_time > (create_time + expires_in - 300)) { // 提前五分钟重新获取access_token
cacheToken = getAccessToken();
}
} else {
cacheToken = getAccessToken();
}
String access_token = cacheToken.get("access_token");
String productId = jsonObject.getString("productId");
String packageName = jsonObject.getString("packageName");
String purchaseToken = jsonObject.getString("purchaseToken");
int purchaseState = jsonObject.getIntValue("purchaseState");
String orderId = jsonObject.getString("orderId");
log.info("productId:{},packageName:{},purchaseToken:{},purchaseState:{},orderId:{}",productId,packageName,purchaseToken,purchaseState,orderId);
Order go = orderRepository.findByTransactionId(orderId);
if (go!=null){
throw new HttpRequestException(HttpServletResponse.SC_NOT_ACCEPTABLE,this.i18n("this.order.has.been.successfully.recharged.and.cannot.be.refilled"));
}
try {
final String client_id = googlePayConfig.getClient_id();
final String client_secret = googlePayConfig.getClient_secret();
final String refresh_token = googlePayConfig.getRefresh_token();
HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
TokenResponse tokenResponse = new TokenResponse();
tokenResponse.setAccessToken(access_token);
tokenResponse.setRefreshToken(refresh_token);
tokenResponse.setExpiresInSeconds(3600L);
tokenResponse.setTokenType("Bearer");
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(transport)
.setJsonFactory(JacksonFactory.getDefaultInstance())
.setClientSecrets(client_id, client_secret)
.build()
.setFromTokenResponse(tokenResponse);
AndroidPublisher publisher = new AndroidPublisher.Builder(transport, JacksonFactory.getDefaultInstance(), credential).setApplicationName(packageName).build();
if (type == 1){//订阅型
return googleSubscribe(user, type, localOrder, productId, packageName, purchaseToken, orderId, publisher);

}
AndroidPublisher.Purchases.Products products = publisher.purchases().products();
AndroidPublisher.Purchases.Products.Get product = products.get(packageName, productId, purchaseToken);//消耗型验证
ProductPurchase purchase = product.execute();
log.info("purchase:{}",purchase);
if (purchase.getPurchaseState()==0) {//确认状态为已购买状态
//POST https://www.googleapis.com/androidpublisher/v3/applications/packageName/purchases/products/productId/tokens/token:acknowledge
//Product pro = productService.getByProductId(productId);
Product pro = (Product) redisTemplate.opsForHash().get(Constant.Redis_Product+":"+productId,productId+"");
int amount = pro.getAmount();
int coin = user.getCoin() + amount;
user.setCoin(coin);
userService.updateUser(user);//更新用户coin
log.info("产品的确认状态:{}",purchase.getAcknowledgementState());
if (purchase.getAcknowledgementState()==0){//尚未得到确认
ProductPurchasesAcknowledgeRequest productPurchasesAcknowledgeRequest = new ProductPurchasesAcknowledgeRequest();
productPurchasesAcknowledgeRequest.setDeveloperPayload(purchase.getDeveloperPayload());
AndroidPublisher.Purchases.Products.Acknowledge acknowledge = products.acknowledge(packageName,productId,purchaseToken,productPurchasesAcknowledgeRequest);
acknowledge.execute();
}
localOrder.setTransactionId(orderId);
localOrder.setStatus(Constant.PAY_SUCCESS);
localOrder.setProductId(pro.getId());
localOrder.setQuantity(pro.getAmount());
localOrder.setType(type);//消耗型
orderService.updateOrder(localOrder);
return new ResultUtil<>().setData(coin);
}
} catch (Exception e) {
throw new HttpRequestException(HttpServletResponse.SC_NOT_ACCEPTABLE, this.i18n("order.verification"));
}
return new ResultUtil<>().setErrorMsg(this.i18n("order.verification"));
}

private Result<Object> googleSubscribe(@CurrentUser User user, int type, Order localOrder, String productId, String packageName, String purchaseToken, String orderId, AndroidPublisher publisher) throws IOException {
log.info("订阅验证开始......");
AndroidPublisher.Purchases.Subscriptions subscriptions = publisher.purchases().subscriptions();
AndroidPublisher.Purchases.Subscriptions.Get subscription = subscriptions.get(packageName,productId,purchaseToken);
SubscriptionPurchase subscriptionPurchase = subscription.execute();
log.info("subscriptionPurchase:{}",subscriptionPurchase);
long expiryTimeMillis = subscriptionPurchase.getExpiryTimeMillis();//订阅到期的时间
long startTimeMillis = subscriptionPurchase.getStartTimeMillis();//授予订阅的时间
boolean autoRenewing = subscriptionPurchase.getAutoRenewing();//订阅在达到其当前到期时间时是否将自动续订。
int paymentState = subscriptionPurchase.getPaymentState();//订阅的付款状态: 0付款等待中 1已收到付款 2免费试用 3待推迟的升级
log.info("expiryTimeMillis : {},startTimeMillis : {},autoRenewing : {},paymentState : {},productId:{},acknowledgementState:{}",expiryTimeMillis,startTimeMillis,autoRenewing,paymentState,productId,subscriptionPurchase.getAcknowledgementState());
//Product pro = productService.getByProductId(productId);
Product pro = (Product) redisTemplate.opsForHash().get(Constant.Redis_Product+":"+productId,productId+"");
user.setJoinTime(new Date(startTimeMillis));//会员订阅时间
user.setExpireTime(new Date(expiryTimeMillis));//会员到期时间
String aMember = (String) redisTemplate.opsForValue().get(Constant.Redis_AMember);
String aSuperMember = (String) redisTemplate.opsForValue().get(Constant.Redis_ASMember);
//todo::用户取消订阅的处理,每月续费用户到期时间的更新
if(autoRenewing==false){//不自动续订
int cancelReason =subscriptionPurchase.getCancelReason();//取消原因
if (cancelReason==0){//用户取消了订阅
if (!user.getExpireTime().before(new Date())){
user.setType(Constant.USER_COMMON);
userService.updateUser(user);
return new ResultUtil<>().setErrorMsg(this.i18n("subscription.expires"));
}
}
}
if (paymentState==1||paymentState==2){//付款状态或者是处于试用期
if (productId.equals(aMember)){
user.setType(1);//强者会员
}else if (productId.equals(aSuperMember)){
user.setType(2);//超强者会员
}
}
userService.updateUser(user);
if (subscriptionPurchase.getAcknowledgementState()==0){//尚未得到确认
log.info("确认订阅订单。。。。");
SubscriptionPurchasesAcknowledgeRequest subAckRe = new SubscriptionPurchasesAcknowledgeRequest();
subAckRe.setDeveloperPayload(subscriptionPurchase.getDeveloperPayload());
AndroidPublisher.Purchases.Subscriptions.Acknowledge subAck = subscriptions.acknowledge(packageName,productId,purchaseToken,subAckRe);
subAck.execute();
}
localOrder.setTransactionId(orderId);
localOrder.setStatus(1);
localOrder.setProductId(pro.getId());
localOrder.setType(type);//订阅
orderService.updateOrder(localOrder);

return new ResultUtil<>().setSuccessMsg(this.i18n("successfully"));
}

/* @RequestMapping(value = "/googlePay", method = RequestMethod.POST)
@ApiOperation(value = "谷歌支付方式二:通过请求谷歌api验证")
@Authorization
public Result<Object> googlePlay(@RequestBody Pay.Payment payment, @CurrentUser User user) {
String no = payment.getNo();
Pay.Purchase receipt = payment.getPurchase();
//先校对与本地订单
Order localOrder = orderRepository.findByNo(no);//禁止重复刷单
if (localOrder == null) {
return new ResultUtil<>().setErrorMsg(this.i18n("order.does.not.exist.and.recharge.failed"));
}
JSONObject jsonObject = null;
try {
String json = JsonUtil.objectToJson(receipt);
jsonObject = JSON.parseObject(json);
} catch (JSONException e) {
throw new HttpRequestException(HttpServletResponse.SC_NOT_ACCEPTABLE, this.i18n("data.parsing.failed"));//数据解析失败
}
String productId = jsonObject.getString("productId");
String packageName = jsonObject.getString("packageName");
String purchaseToken = jsonObject.getString("purchaseToken");
int purchaseState = jsonObject.getIntValue("purchaseState");
String orderId = jsonObject.getString("orderId");
log.info("productId:{},packageName:{},purchaseToken:{},purchaseState:{},orderId:{}",productId,packageName,purchaseToken,purchaseState,orderId);
Order go = orderRepository.findByTransactionId(orderId);
if (go!=null){
throw new HttpRequestException(HttpServletResponse.SC_NOT_ACCEPTABLE,this.i18n("this.order.has.been.successfully.recharged.and.cannot.be.refilled"));
}
try {
File file = ResourceUtils.getFile("classpath:/googlePlayKey/rizin_p12.p12");
HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport();
PrivateKey privateKey = SecurityUtils.loadPrivateKeyFromKeyStore(
SecurityUtils.getPkcs12KeyStore(),
new FileInputStream(file), // 生成的P12文件
"notasecret", "privatekey", "notasecret");

GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(transport).setJsonFactory(JacksonFactory.getDefaultInstance())
.setServiceAccountId(googlePayConfig.getServiceAccountEmail()) // e.g.: 626891557797-frclnjv31rn4ss81ch746g9t6pd3mmej@developer.gserviceaccount.com
.setServiceAccountScopes(AndroidPublisherScopes.all())
.setServiceAccountPrivateKey(privateKey).build();

AndroidPublisher publisher = new AndroidPublisher.Builder(transport,
JacksonFactory.getDefaultInstance(), credential).build();

AndroidPublisher.Purchases.Products products = publisher.purchases().products();

// 参数详细说明: https://developers.google.com/android-publisher/api-ref/purchases/products/get
AndroidPublisher.Purchases.Products.Get product = products.get(packageName,
productId, purchaseToken);
log.info("credential:{},publisher:{},products:{},product:{}",credential,publisher,products,product);
// 获取订单信息
// 返回信息说明: https://developers.google.com/android-publisher/api-ref/purchases/products
// 通过consumptionState, purchaseState可以判断订单的状态
ProductPurchase purchase = product.execute();
log.info("purchaseis : {}",purchase);
if (purchase.getPurchaseState()==0) {
Product pro = productService.getByProductId(productId);
int amount = pro.getAmount();
BigDecimal price = pro.getPrice();
int coin = user.getCoin() + amount;
user.setCoin(coin);
userService.updateUser(user);//更新用户coin
localOrder.setTransactionId(orderId);
localOrder.setStatus(1);
//todo::充值类型是消耗型还是订阅型 type赋值
localOrder.setProductId(pro.getId());
orderService.updateOrder(localOrder);
return new ResultUtil<>().setData(coin);

}
} catch (Exception e) {
throw new HttpRequestException(HttpServletResponse.SC_NOT_ACCEPTABLE, this.i18n("order.verification"));
}
return new ResultUtil<>().setErrorMsg(this.i18n("order.verification"));
}

*/
private Map<String, String> getAccessToken() {
String client_id = googlePayConfig.getClient_id();
String client_secret = googlePayConfig.getClient_secret();
String refresh_token = googlePayConfig.getRefresh_token();
Map<String, String> headers = new HashMap<>();
Map<String, String> querys = new HashMap<>();
Map<String, String> map = null;
try {
// HTTP 获取access_token
String url = "https://accounts.google.com/o/oauth2/token";
headers.put("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
headers.put("Accept", "text/plain;charset=utf-8");
querys.put("grant_type", "refresh_token");
querys.put("client_id", client_id);
querys.put("client_secret", client_secret);
querys.put("refresh_token", refresh_token);
String googleAccessToken = HttpUtils.send(url, headers, querys, "UTF-8");
JSONObject tokenObject = JSON.parseObject(googleAccessToken);
String access_token = tokenObject.getString("access_token");
Long expires_in = tokenObject.getLong("expires_in");
map = new HashMap<String, String>();
map.put("access_token", access_token);
map.put("expires_in", String.valueOf(expires_in));
// 带入access_token的创建时间,用于之后判断是否失效
map.put("create_time", String.valueOf((new Date().getTime()) / 1000));
log.info("包含access_token的JSON信息为: {}", tokenObject);
} catch (MalformedURLException e) {
log.error("获取access_token失败,原因是:{}", e);
e.printStackTrace();
} catch (IOException e) {
log.error("获取access_token失败,原因是:{}", e);
e.printStackTrace();
}
return map;
}

Pay.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package com.xy.goone.modules.model;

import java.util.Date;
import java.util.List;

/**
* @author fumei.jiang
* @date 2019-12-05 16:05
*/
public class Pay {

public static class Payment{
private int type;//类型:0消耗 1订阅

private String no;//本地订单号

private Purchase purchase;

public Payment(int type, String no, Purchase purchase) {
this.type = type;
this.no = no;
this.purchase = purchase;
}

public int getType() {
return type;
}

public void setType(int type) {
this.type = type;
}

public String getNo() {
return no;
}

public void setNo(String no) {
this.no = no;
}

public Purchase getPurchase() {
return purchase;
}

public void setPurchase(Purchase purchase) {
this.purchase = purchase;
}
}
public static class Purchase {
private String productId;
private String purchaseToken;
private String purchaseState;
private String packageName;
private String orderId;
private boolean acknowledged;

public String getPurchaseToken() {
return purchaseToken;
}

public void setPurchaseToken(String purchaseToken) {
this.purchaseToken = purchaseToken;
}

public String getPurchaseState() {
return purchaseState;
}

public void setPurchaseState(String purchaseState) {
this.purchaseState = purchaseState;
}

public String getPackageName() {
return packageName;
}

public void setPackageName(String packageName) {
this.packageName = packageName;
}

public String getOrderId() {
return orderId;
}

public void setOrderId(String orderId) {
this.orderId = orderId;
}

public String getProductId() {
return productId;
}

public void setProductId(String productId) {
this.productId = productId;
}

public boolean isAcknowledged() {
return acknowledged;
}

public void setAcknowledged(boolean acknowledged) {
this.acknowledged = acknowledged;
}
}

好啦,基本代码差不多就是这些了。在对接过程中,我又几点要提示的。

Tips

  • 谷歌测试账号下单五分钟内没有任何操作比如验证确认消耗就会自动取消该订单,消耗型的产品需在三天内确认订单,否则此订单无效。
  • 确认订单可以在服务端或客户端进行,但是消耗型商品需要进行消耗(订阅型商品不需要进行消耗),服务端只能确认不能消耗产品,验证并确认完毕的产品需要客户端进行消耗,否则下次购买时将不允许再次购买。
  • 谷歌支付生产订阅和测试订阅的周期不同,如下图:
  • 如果是测试账号的订阅,最多可续订6次。
    如果是用测试账号来进行订阅的话,因为周期非常短,一个月循环5分钟就会到期,而一年的循环30分钟分钟就会到期。
    而且这种测试订阅最多可续订6次,也就是从刚开始订阅 {subId} 到 {subId}…5 这样子,最多6单过来之后,接下来 google 那边就会发过来取消循环的 webhook 了,然后就取消循环了。
    具体的文档:测试订阅续订
    感谢您的浏览,希望对您有所帮助!

Google iap webhook 接入(2) - 项目接入GCP webhook

欣赏此文?求鼓励,求支持!