转自:https://www.jianshu.com/p/976fc6090cfa
官方验证文档地址:Apple Developer Documentation
进行代码前,首先使用postman将收据发送给苹果服务器,熟悉一下返回的数据结构
?工具类
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内购验证工具类
* Created by wangqichang on 2019/2/26.
*/
public class IosVerifyUtil {
private static class TrustAnyTrustManager implements X509TrustManager {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[] {};
}
}
private static class TrustAnyHostnameVerifier implements HostnameVerifier {
public boolean verify(String hostname, SSLSession session) {
return true;
}
}
private static final String url_sandbox = "https://sandbox.itunes.apple.com/verifyReceipt";
private static final String url_verify = "https://buy.itunes.apple.com/verifyReceipt";
/**
* 苹果服务器验证
*
* @param receipt
* 账单
* @url 要验证的地址
* @return null 或返回结果 沙盒 https://sandbox.itunes.apple.com/verifyReceipt
*
*/
public static String buyAppVerify(String receipt,int type) {
//环境判断 线上/开发环境用不同的请求链接
String url = "";
if(type==0){
url = url_sandbox; //沙盒测试
}else{
url = url_verify; //线上测试
}
//String url = EnvUtils.isOnline() ?url_verify : url_sandbox;
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", "text/json");
conn.setRequestProperty("Proxy-Connection", "Keep-Alive");
conn.setDoInput(true);
conn.setDoOutput(true);
BufferedOutputStream hurlBufOus = new BufferedOutputStream(conn.getOutputStream());
JSONObject obj = new JSONObject();
obj.put("receipt-data", receipt);
//自动续费产品加上password
// obj.put("password", "**************");
hurlBufOus.write(obj.toString().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;
}
}
代码JSON包用的hutool的包,需要自行引入或调整代码
public R applePayOrderNotifyCallBack(String transactionId, String payload) {
//1.先线上测试 发送平台验证
String verifyResult = IosVerifyUtil.buyAppVerify(payload, 1);
//苹果服务器没有返回验证结果
if (verifyResult == null) {
logger.info("无订单信息!");
R.fail("无订单信息");
}
// 苹果验证有返回结果
logger.info("线上,苹果平台返回JSON:" + verifyResult);
JSON job = JSONUtil.parse(verifyResult);
String states = job.getByPath("status").toString();
//0 正常
//21000 App Store不能读取你提供的JSON对象
//21002 receipt-data域的数据有问题
//21003 receipt无法通过验证
//21004 提供的shared secret不匹配你账号中的shared secret
//21005 receipt服务器当前不可用
//21006 receipt合法,但是订阅已过期。服务器接收到这个状态码时,receipt数据仍然会解码并一起发送
//21007 receipt是Sandbox receipt,但却发送至生产系统的验证服务
//21008 receipt是生产receipt,但却发送至Sandbox环境的验证服务
if ("21007".equals(states)) { //是沙盒环境,应沙盒测试,否则执行下面
//2.再沙盒测试 发送平台验证
verifyResult = IosVerifyUtil.buyAppVerify(payload, 0);
logger.info("沙盒环境,苹果平台返回JSON:" + verifyResult);
job = JSONUtil.parse(verifyResult);
states = job.getByPath("status").toString();
}
logger.info("苹果平台返回值:job" + job);
if (states.equals("0")) { // 前端所提供的收据是有效的 验证成功
JSON inAppJson = JSONUtil.parse(JSONUtil.getByPath(job, "receipt.in_app"));
List<JSON> jsons = JSONUtil.toList(inAppJson.toString(), JSON.class);
//所有支付成功的订单号
List<String> transaction_id =
jsons.stream().map(t -> t.getByPath("transaction_id").toString())
.distinct().collect(Collectors.toList());
if(transaction_id.contains(transactionId)){
return R.ok();
}
return R.fail();
} else {
return R.fail("receipt数据有问题");
}
}
|