一.苹果支付
①逻辑流程图
二.苹果支付流程介绍
①用户购买产品下发支付请求到app端;
②app端收到请求后调用苹果服务进行支付扣款;
③苹果服务扣款成功后返回receipt_data加密数据和支付订单号order_id给app端;
④app端将返回的数据receipt_data及order_id,请求java服务的验证接口;
⑤java服务收到参数后去请求苹果服务验证用户在app端上支付的结果;
(注:receipt_data加密数据不需要在java服务解密,直接传给苹果服务)
⑥苹果服务将验证的结果及交易信息返回给java服务,java服务根据返回的结果处理自己的业务;
⑦java服务处理完自己的业务后,将结果返回给app端;
②app端再请求苹果服务检查java服务是否已经验证;
③苹果服务告知app端,java服务是否验证;
⑧app端根据苹果服务返回的验证结果通知用户订单是否结束;
三.java代码
controller
package com.insigma.mmlove.admin.controller;
import com.insigma.mmlove.admin.service.ApplePayService;
import com.insigma.mmlove.admin.util.ApplePayUtil;
import com.insigma.mmlove.common.api.Result;
import com.insigma.mmlove.common.api.ResultCode;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@Slf4j
@RestController
@Api(tags = {"苹果内购"})
@RequestMapping(value = "/apple")
public class ApplePayController {
@Autowired
ApplePayService applePayService;
@Autowired
ApplePayUtil applePayUtil;
/**
* @param :TransactionID订单号
* @param :receipt订单加密收据
* @Description: Ios客户端内购支付
*/
@RequestMapping("/applePay")
public Result doIosRequest(@RequestParam("receipt") String receipt, @RequestParam("TransactionID") String TransactionID) {
String verifyResult = applePayUtil.buyAppVerify(receipt, 0);
//苹果服务器没有返回验证结果
if (verifyResult == null) {
return Result.failed(ResultCode.APPLE_NULL);
} else {
return applePayService.getAppPay(verifyResult, TransactionID);
}
}
}
service
package com.insigma.mmlove.admin.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.insigma.mmlove.admin.service.ApplePayService;
import com.insigma.mmlove.common.api.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Service
@Slf4j
public class ApplePayServiceImpl implements ApplePayService {
@Override
public Result getAppPay(String verifyResult, String transactionID) {
JSONObject jsonObject = JSONObject.parseObject(verifyResult);
String status = jsonObject.getString("status");
//判断是否验证成功
if ("0".equals(status)) {
//app端所提供的收据是有效的,验证成功
String receipt = jsonObject.getString("receipt");
JSONObject returnJson = JSONObject.parseObject(receipt);
String in_app = returnJson.getString("in_app");
JSONObject in_appJson = JSONObject.parseObject(in_app.substring(1, in_app.length() - 1));
String transactionId = in_appJson.getString("transaction_id");
String in_app_ownership_type = in_appJson.getString("in_app_ownership_type");
//如果验证后的订单号与app端传来的订单号一致并且状态为已支付状态则处理自己的业务
if (transactionID.equals(transactionId) && "PURCHASED".equals(in_app_ownership_type)) {
//===================处理自己的业务 ============================
}
}
return Result.failed("苹果内购验证失败");
}
}
util
package com.insigma.mmlove.admin.util;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
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;
@Component
public class ApplePayUtil {
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;
}
}
@Value("${applepay.verifyUrl}")
private String url_apple_pay;
@Value("${applepay.verifyTestUrl}")
private String test_url_apple_pay;
/**
* 苹果服务器验证
*
* @param receipt 账单
* @return null 或返回结果
* @url 要验证的地址 沙盒 https://sandbox.itunes.apple.com/verifyReceipt
*/
public String buyAppVerify(String receipt, int type) {
//环境判断 线上/开发环境用不同的请求链接
try {
String url = null;
if (type == 0) {
url = test_url_apple_pay; //沙盒环境,测试
} else {
url = url_apple_pay; //线上环境
}
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);
conn.setConnectTimeout(3000);
BufferedOutputStream hurlBufOus = new BufferedOutputStream(conn.getOutputStream());
//拼成固定的格式传给平台
String str = String.format(Locale.CHINA, "{\"receipt-data\":\"" + receipt + "\"}");
// 直接将receipt当参数发到苹果验证就行,不用拼格
//String str = String.format(Locale.CHINA, receipt);
hurlBufOus.write(str.getBytes());
hurlBufOus.flush();
InputStream is = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
StringBuilder sb = new StringBuilder();
while ((line = reader.readLine()) != null) {
sb.append(line);
}
return sb.toString();
} catch (Exception ex) {
System.out.println("苹果服务器异常");
ex.printStackTrace();
}
return null;
}
}
参考链接:
- https://blog.csdn.net/m0_62949970/article/details/124570436
- http://www.360doc.com/content/22/0726/22/10087950_1041513199.shtml
- https://www.jianshu.com/p/51f2cf328481