Java实现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内购验证工具类
 */  

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 支付凭证
     * @param type 1=生产环境;0=沙盒环境
     */
    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());  

            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;  

    }

    /**
     * 用BASE64加密
     *
     * @param str
     * @return
     */
    public static String getBASE64(String str) {  

        byte[] b = str.getBytes();  

        String s = null;  

        if (b != null) {  

            s = new sun.misc.BASE64Encoder().encode(b);  

        }  

        return s;  

    }

} 

下单和回调接口

import com.alibaba.fastjson.JSONObject;
import plugins.pay.ios.IosVerifyUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.List;

@RestController
@Api(tags="支付接口")
@RequestMapping("/Indent")
public class H5IndentController {

    @GetMapping("/addIOS")
    @ApiOperation(value = "iOS内购新增订单", notes = "iOS内购新增订单")
    public String addWechat(HttpServletRequest request, HttpServletResponse response){

        // TODO 保存数据


        return "商户订单id";
    }

    /**
     * 苹果内购支付回调
     * @param TransactionID 内购项目编号,不用管(感觉应该是每条支付凭证的一个唯一id,可以用来确定订单是否处理)
     * @param Payload BASE64的验证字符串
     * @param indentId 数据库订单id
     */
    @PostMapping("/iosNotify")
    public int doIosRequest(String TransactionID, String Payload, Long indentId) throws Exception {

        // 解析支付凭证
        String verifyResult =  IosVerifyUtil.buyAppVerify(Payload,1);

        if (verifyResult == null) {
            return 10010;
        } else {

            // 获取支付凭证状态
            JSONObject job = JSONObject.parseObject(verifyResult);
            String states = job.getString("status");

            // 沙盒环境
            if("21007".equals(states)){

                // 获取沙盒环境凭证信息
                verifyResult =  IosVerifyUtil.buyAppVerify(Payload,0);
                job = JSONObject.parseObject(verifyResult);
                states = job.getString("status");
            }

            // 处理订单
            if (states.equals("0")) {
                String receipt = job.getString("receipt");
                JSONObject returnJson = JSONObject.parseObject(receipt);
                String inApp = returnJson.getString("in_app");
                List<HashMap> inApps = JSONObject.parseArray(inApp, HashMap.class);
                if (!CollectionUtils.isEmpty(inApps)) {

                    // 循环处理订单
                    for (HashMap app: inApps) {

                        // 查询交易是否处理
                        String transactionId = (String) app.get("transaction_id");
                        // TODO 获取到订单id后,需要自行判断这个订单是否处理,transactionId这个值每个订单时独立的,但是iOS的
                        //  回调每次会把所有的订单都返给回调接口,所有我没要进行判断

                        // TODO 处理业务逻辑
                        updateIndent(indentId + "", transactionId);
                    }
                    return 200;
                }
                return 10011;
            } else {
                return 10012;
            }

        }

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值