java内购_java后台接入IOS内购

参考文档

说明

后台处理:将购买凭证(接收IOS端)发送到苹果的服务器验证,并将验证结果返回给客户端。

代码

工具类

import javax.net.ssl.*;

import java.io.BufferedOutputStream;

import java.io.BufferedReader;

import java.io.InputStream;

import java.io.InputStreamReader;

import java.net.URL;

import java.security.cert.CertificateException;

import java.security.cert.X509Certificate;

import java.util.Locale;

/**

* 苹果IAP内购验证工具类

*

* 官网:https://developer.apple.com/documentation/storekit/in-app_purchase

* 参考:https://blog.csdn.net/lbd_123/article/details/87276204

* @author xiaoqiang

* @date 2020-05-11 14:37

*/

public class IosVerifyUtil {

private static class TrustAnyTrustManager implements X509TrustManager {

@Override

public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

}

@Override

public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

}

@Override

public X509Certificate[] getAcceptedIssuers() {

return new X509Certificate[] {};

}

}

private static class TrustAnyHostnameVerifier implements HostnameVerifier {

@Override

public boolean verify(String hostname, SSLSession session) {

return true;

}

}

/**

* 苹果服务器验证

*

* @param receipt

* 账单

* @url 要验证的地址

* @return null 或返回结果 沙盒 https://sandbox.itunes.apple.com/verifyReceipt

*

* 21000App Store无法读取你提供的JSON数据

* 21002 订单数据不符合格式

* 21003 订单无法被验证

* 21004 你提供的共享密钥和账户的共享密钥不一致

* 21005 订单服务器当前不可用

* 21006 订单是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中

* 21007 订单信息是测试用(sandbox),但却被发送到产品环境中验证

* 21008 订单信息是产品环境中使用,但却被发送到测试环境中验证

*/

public static String buyAppVerify(String receipt,int type) {

String url_sandbox = "https://sandbox.itunes.apple.com/verifyReceipt";

String url_verify = "https://buy.itunes.apple.com/verifyReceipt";

// 环境判断 线上/开发环境用不同的请求链接

String url = "";

if(type==0){

// 沙盒测试

url = url_sandbox;

}else{

// 线上测试

url = url_verify;

}

try {

SSLContext sc = SSLContext.getInstance("SSL");

sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());

URL console = new URL(url);

HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();

conn.setSSLSocketFactory(sc.getSocketFactory());

conn.setHostnameVerifier(new TrustAnyHostnameVerifier());

conn.setRequestMethod("POST");

conn.setRequestProperty("Content-Type","application/json");

conn.setRequestProperty("Proxy-Connection", "Keep-Alive");

conn.setDoInput(true);

conn.setDoOutput(true);

BufferedOutputStream hurlBufOus = new BufferedOutputStream(conn.getOutputStream());

// 拼成固定的格式传给平台

String str = String.format(Locale.CHINA, "{\"receipt-data\":\"" + receipt + "\"}");

hurlBufOus.write(str.getBytes());

hurlBufOus.flush();

InputStream is = conn.getInputStream();

BufferedReader reader = new BufferedReader(new InputStreamReader(is));

String line = null;

StringBuffer sb = new StringBuffer();

while ((line = reader.readLine()) != null) {

sb.append(line);

}

return sb.toString();

} catch (Exception ex) {

System.out.println("苹果服务器异常");

ex.printStackTrace();

}

return null;

}

}

业务代码片段

import com.alibaba.fastjson.JSONArray;

import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;// 日志用了lombok,报错可以将log相关删除

/**

*@param productId 商品ID

*@param receipt 购买凭证

*/

public Result iosInAppPurchase(String productId, String receipt) {

if (StringUtils.isBlank(receipt)){

return Result.fail("receipt不能为空");

}

if (StringUtils.isBlank(productId)){

return Result.fail("productId不能为空");

}

// 0沙盒 非0即线上

String verifyResult = IosVerifyUtil.buyAppVerify(receipt, 0);

if (StringUtils.isBlank(verifyResult)) {// 苹果服务器没有返回验证结果

log.info("IOS内购(充值)=>苹果服务器没有返回验证结果");

return Result.error("苹果服务器没有返回验证结果");

} else {// 苹果验证有返回结果

JSONObject job = JSONObject.parseObject(verifyResult);

log.info("IOS内购(充值)=>苹果服务器返回验证结果:{}", job);

String states = job.getString("status");

//是沙盒环境,应沙盒测试,否则执行下面

if ("21007".equals(states)) {

//2.在沙盒测试 发送平台验证

verifyResult = IosVerifyUtil.buyAppVerify(receipt, 0);

job = JSONObject.parseObject(verifyResult);

states = job.getString("status");

}

if (states.equals("0")) { // 前端所提供的收据是有效的 验证成功

String r_receipt = job.getString("receipt");

JSONObject returnJson = JSONObject.parseObject(r_receipt);

String in_app = returnJson.getString("in_app");

JSONArray jsonArray = JSONArray.parseArray(in_app);

log.info("IOS内购(充值)=>苹果服务器返回验证结果订单数量:{}", jsonArray.size());

for (int i = 0; i < jsonArray.size(); i++) {

if (rechargeBallCoinIosVo.getBallCoinRechargeId().equals(jsonArray.getJSONObject(i).get("product_id") == null ? null : jsonArray.getJSONObject(i).get("product_id").toString())) {

// 订单号

String transactionId = jsonArray.getJSONObject(i).get("transaction_id") == null ? null : jsonArray.getJSONObject(i).get("transaction_id").toString();

/* 自己的业务处理 */

// 1.创建订单信息

// 2. 增加用户虚拟币数量

// 3. 添加用户消费记录

}

}

} else {

return Result.error(job);

}

}

return Result.success();

}

统一返回结果

import java.util.HashMap;

import java.util.Objects;

/**

* @author xiaoqiang

* @Description 返回结果信息

* @date 2019/3/21 16:50

*/

public class Result extends HashMap {

public static String CODE_KEY = "code";

public static String MSG_KEY = "msg";

public static String DATA_KEY = "data";

/**

* 调用结果(-1 异常 0 失败 1 成功)

*/

public enum CallResult {

/**

* 异常

*/

ERROR(-1, "异常"),

/**

* 失败

*/

FAIL(0, "失败"),

/**

* 成功

*/

SUCCESS(1, "成功");

/**

* code码

*/

private Integer code;

/**

* 提示信息

*/

private String msg;

private CallResult(Integer code, String msg) {

this.code = code;

this.msg = msg;

}

public Integer getCode() {

return code;

}

public String getMsg() {

return msg;

}

}

/**

*

*/

private static final long serialVersionUID = 1L;

/**

* 成功

*

* @return

*/

public static Result success() {

Result result = new Result();

result.put(CODE_KEY, Result.CallResult.SUCCESS.getCode());

result.put(MSG_KEY, Result.CallResult.SUCCESS.getMsg());

result.put(DATA_KEY, null);

return result;

}

public static Result success(String msg) {

Result result = success();

result.put(MSG_KEY, msg);

return result;

}

public static Result success(ResultCode code, Object obj) {

Result result = success();

result.put(CODE_KEY, code.code());

result.put(MSG_KEY, code.msg());

result.put(DATA_KEY, obj);

return result;

}

public static Result success(Object obj) {

Result result = success();

result.put(DATA_KEY, obj);

return result;

}

public static Result success(String msg, Object obj) {

Result result = success();

result.put(MSG_KEY, msg);

result.put(DATA_KEY, obj);

return result;

}

/**

* 失败

*

* @return

*/

public static Result fail() {

Result result = new Result();

result.put(CODE_KEY, Result.CallResult.FAIL.getCode());

result.put(MSG_KEY, Result.CallResult.FAIL.getMsg());

result.put(DATA_KEY, null);

return result;

}

public static Result fail(String msg) {

Result result = fail();

result.put(MSG_KEY, msg);

return result;

}

public static Result fail(ResultCode code, Object obj) {

Result result = fail();

result.put(CODE_KEY, code.code());

result.put(MSG_KEY, code.msg());

result.put(DATA_KEY, obj);

return result;

}

public static Result fail(Object obj) {

Result result = fail();

result.put(DATA_KEY, obj);

return result;

}

public static Result fail(String msg, Object obj) {

Result result = fail();

result.put(MSG_KEY, msg);

result.put(DATA_KEY, obj);

return result;

}

/**

* 异常

*

* @return

*/

public static Result error() {

Result result = new Result();

result.put(CODE_KEY, Result.CallResult.ERROR.getCode());

result.put(MSG_KEY, Result.CallResult.ERROR.getMsg());

result.put(DATA_KEY, null);

return result;

}

public static Result error(String msg) {

Result result = error();

result.put(MSG_KEY, msg);

return result;

}

public static Result error(Object obj) {

Result result = error();

result.put(DATA_KEY, obj);

return result;

}

public static Result error(String msg, Object obj) {

Result result = error();

result.put(MSG_KEY, msg);

result.put(DATA_KEY, obj);

return result;

}

/**

* 自定义

*

* @param code

* @param msg

* @param obj

* @return

*/

public static Result custom(Object code, Object msg, Object obj) {

Result result = new Result();

result.put(CODE_KEY, code);

result.put(MSG_KEY, msg);

result.put(DATA_KEY, obj);

return result;

}

/**

* 自定义返回

* @param code

* @param obj

* @return

*/

public static Result custom(ResultCode code, Object obj) {

Result result = new Result();

result.put(CODE_KEY, code.code());

result.put(MSG_KEY, code.msg());

result.put(DATA_KEY, obj);

return result;

}

/**

*

* @return

*/

public static Result notLogin(){

Result result = new Result();

result.put(CODE_KEY, ResultCode.NOT_LOGIN.code());

result.put(MSG_KEY, ResultCode.NOT_LOGIN.msg());

result.put(DATA_KEY, null);

return result;

}

/**

* 验证成功

* @param result

* @return

*/

public static boolean isSuccess(Result result) {

return !Objects.isNull(result.get(CODE_KEY)) && (Integer) result.get(CODE_KEY) == 1;

}

}

购买凭证解析后JSON数据样列

{

"environment": "Sandbox",

"receipt": {

"in_app": [

{

"transaction_id": "1000000665290365",

"original_purchase_date": "2020-05-15 09:08:45 Etc/GMT",

"quantity": "1",

"original_transaction_id": "1000000665290365",

"purchase_date_pst": "2020-05-15 02:08:45 America/Los_Angeles",

"original_purchase_date_ms": "1589533725000",

"purchase_date_ms": "1589533725000",

"product_id": "1237265852472238082",

"original_purchase_date_pst": "2020-05-15 02:08:45 America/Los_Angeles",

"is_trial_period": "false",

"purchase_date": "2020-05-15 09:08:45 Etc/GMT"

}

],

"adam_id": 0,

"receipt_creation_date": "2020-05-15 09:08:46 Etc/GMT",

"original_application_version": "1.0",

"app_item_id": 0,

"original_purchase_date_ms": "1375340400000",

"request_date_ms": "1589533728625",

"original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles",

"original_purchase_date": "2013-08-01 07:00:00 Etc/GMT",

"receipt_creation_date_pst": "2020-05-15 02:08:46 America/Los_Angeles",

"receipt_type": "ProductionSandbox",

"bundle_id": "com.bzsports.bz",

"receipt_creation_date_ms": "1589533726000",

"request_date": "2020-05-15 09:08:48 Etc/GMT",

"version_external_identifier": 0,

"request_date_pst": "2020-05-15 02:08:48 America/Los_Angeles",

"download_id": 0,

"application_version": "6338"

},

"status": 0

}

你可能感兴趣的:(java内购)