Java内购接入Apple Pay、Google play
内购流程:
- 客户端向服务器发起请求生成预订单,服务器校验后生成预订单返回客户端。若调起支付界面后未支付,则通知服务器取消本订单。
- 客户端拿到预订单号后,在玩家完成付款操作后,携带预订单号请求支付平台,将预订单号存储在支付平台中,并获取支付凭证。
- 客户端携带支付凭证请求服务器,服务器携带支付凭证向支付平台请求
- 服务器收到支付平台的回值后,从回值中获取订单的支付状态和预订单号,并通过预订单号定位玩家具体购买的商品信息。
- 服务器返回客户端校验信息,客户端通知支付平台本单已结束
内购失败处理方式:
- 校验失败(网络波动,支付平台状态更新异常,玩家使用重复支付凭证)则先存储校验时需要的参数,例如,支付凭证,transactionId等信息,存储在数据库和ck中
- 在后台中创建定时,限次数的进行后台校验。重新携带参数请求支付平台,若校验通过,则通过邮件形式向玩家发邮件进行补偿。在达到校验最大次数后仍未通过校验,则此单不再参与后台自动校验。
- 未通过校验的玩家可以通过联系客服进行再次校验。客服可以通过远程脚本手动查看支付平台返回的校验信息,核实后向玩家发邮件补偿,并手动记录在ck中。
客户端逻辑:
客户端先向支付平台请求正在支付的列表,若存在未完成到订单,则像服务器发送校验请求,直到服务器向客户端返回信息,客户端会向支付平台发起结束本订单的请求,完成完整的一次内购。
校验代码:
Apple Pay:
public AppleResponseData getIosOrderId(String transactionId, String url) {
try {
Map<String, Object> header = new HashMap<>();
header.put("alg", "ES256");
header.put("kid", new String(Base64.getDecoder().decode(iosKid.getBytes())));
header.put("typ", "JWT");
Map<String, Object> claims = new HashMap<>();
claims.put("iss", new String(Base64.getDecoder().decode(iosIss.getBytes())));
claims.put("iat", Math.floor(System.currentTimeMillis() / 1000));
claims.put("exp", Math.floor(System.currentTimeMillis() / 1000) + 1800);
claims.put("aud", "appstoreconnect-v1");
claims.put("bid", iosBid);
//从p8文件获取的秘钥 此处为了方便演示直接使用的字符串,建议从p8文件中读取,确保安全性
String key = iosPrivateKey;
PrivateKey privateKey = null;
//ES256无法使用Base64加密的秘钥来生成jwt 必须解码
KeyFactory kf = KeyFactory.getInstance("EC");
privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.getDecoder().decode(key)));
//生成jwt
String token = Jwts.builder()
.setHeader(header)
.setClaims(claims)
.signWith(SignatureAlgorithm.ES256, privateKey)
.compact();
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[]{new TrustAnyTrustManager()},
new java.security.SecureRandom());
URL console = new URL(url + transactionId);
HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
conn.setSSLSocketFactory(sc.getSocketFactory());
conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
conn.setRequestMethod("GET");
conn.setRequestProperty("content-type", "text/json");
conn.setRequestProperty("Proxy-Connection", "Keep-Alive");
conn.setRequestProperty("Authorization", "Bearer "+ token);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setConnectTimeout(3000);
InputStream is = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = "";
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
JSONObject jsonObject = JSONObject.parseObject(sb.toString());
LogUtil.trace("ios支付回值:" + jsonObject);
String jwsTransactionBase64 = jsonObject.getString("signedTransactionInfo").split("\\.")[1];
String jwsTransactionBase = new String(Base64.getDecoder().decode(jwsTransactionBase64));
AppleResponseData appleResponseData = JSONObject.parseObject(jwsTransactionBase, new TypeReference<AppleResponseData>() {});
return appleResponseData;
} catch (Exception e) {
CommonLogUtil.error(e.getMessage(), e);
}
return null;
}
接收类:
public class AppleResponseData {
//服务器uuid
private String appAccountToken;
//应用包名
private String bundleId;
private String currency;
//沙盒或者正式环境
private String environment;
//购买时间
private long originalPurchaseDate;
//产品id
private String productId;
//唯一标识
private String transactionId;
}
官方文档: https://developer.apple.com/documentation/appstoreserverapi/get_transaction_history
需要参数:文章来源:https://www.toymoban.com/news/detail-853812.html
- transactionId:支付完成后客户端从IOS平台获取的支付凭证。
- url:服务器校验地址,
沙盒:https://api.storekitsandbox.itunes.apple.com/inApps/v1/transactions/ (+ transactionId)
正式:https://api.storekit.itunes.apple.com/inApps/v1/history/ (+ transactionId) - kid:密钥id
- iss:issuer ID
- bid:应用名称,例如 com.company.production
- privateKey:已授权账号在ios官网下载的p8文件中的内容
Google Play:
public ProductPurchase googlePlayPayRequest(String productId, String purchaseToken,
String packageName) {
try {
openTemProxy();
List<String> scopes = new ArrayList<>();
scopes.add(AndroidPublisherScopes.ANDROIDPUBLISHER);
StringInputStream stringInputStream = new StringInputStream(new String(Base64.getDecoder().decode(googleVerifyJson)));
GoogleCredential credential = GoogleCredential.fromStream(stringInputStream)
.createScoped(scopes);
//设置过期时间
credential.setExpirationTimeMilliseconds(3000L);
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = new JacksonFactory();
AndroidPublisher publisher = new AndroidPublisher.Builder(httpTransport, jsonFactory,
credential).build();
AndroidPublisher.Purchases purchases = publisher.purchases();
final AndroidPublisher.Purchases.Products.Get request = purchases.products()
.get(packageName, productId, purchaseToken);
return request.execute();
} catch (Exception e) {
LogUtil.info(e.getMessage(), e);
} finally {
Properties systemProperties = System.getProperties();
if(openProxy){
systemProperties.clear();
}
}
return null;
}
/**
* 开启代理
*/
public void openTemProxy() {
if(true){
//代理端口
try {
Properties systemProperties = System.getProperties();
systemProperties.setProperty("http.proxyHost", "127.0.0.1");
systemProperties.setProperty("http.proxyPort", "7890");
systemProperties.setProperty("https.proxyHost", "127.0.0.1");
systemProperties.setProperty("https.proxyPort", "7890");
systemProperties.setProperty("socksProxyHost", "127.0.0.1");
systemProperties.setProperty("socksProxyPort", "7890");
systemProperties.setProperty("http.nonProxyHosts", "localhost");
systemProperties.setProperty("https.nonProxyHosts", "localhost");
} catch (Exception e) {
CommonLogUtil.error(e.getMessage(), e);
}
}
}
maven:
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-androidpublisher</artifactId>
<version>v3-rev24-1.24.1</version>
</dependency>
<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>1.3.0</version>
</dependency>
官方文档: https://developers.google.cn/android-publisher/api-ref/rest/v3/purchases.products?skip_cache=true&hl=zh-cn
需要参数:
- productId: 产品id
- purchaseToken: 购买凭证
- packageName: 项目名称
- verifyJson: google后台获取授权账号json文件
google授权文档: https://www.quicksdk.com/doc-516.html文章来源地址https://www.toymoban.com/news/detail-853812.html
到了这里,关于Java接入内购 Apple Pay、Google Play的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!