java 苹果支付(内购)

1、app配置苹果内购项目(iOS系统app端负责)

https://help.apple.com/app-store-connect/#/devb57be10e7

  • APP store 配置APP项目

  • 项目下添加内购项目

  • 添加沙盒测试账号

2.iOS-iOS内购流程(手把手图文教程)_CC__超的博客-CSDN博客_ios内购流程//这个地址有ios系统app申请账号权限等教程;

3.requestBody | Apple Developer Documentation//苹果内购官网验证接口请求参数

4.verifyReceipt | Apple Developer Documentation//苹果官网内购验证接口返回参数及调用地址

5.status | Apple Developer Documentation//官网状态码

一.苹果支付

 ①逻辑流程图

java 苹果支付(内购)_第1张图片

二,苹果支付流程介绍

①户在app端购买产品下发支付请求指令app;
②app获取用户购买的信息及指令请求苹果系统服务后台进行支付扣,;
③苹果系统服务器扣款成功后返回receipt_data加密数据和支付订单号order_id给app端;
④app端直接将返回的数据及订单号,请求java后台的验证接口;
⑤java后端直接通过HttpsURLConnection将app端携带来的参数以及验证地址url请求苹果系统服务器验证用户在app端支付的结果;(注:receipt_data加密数据不需要在java后台解密,直接传给苹果服务器)
⑥苹果系统服务器将验证的结果及订单产品信息返回给java后台服务器,java后台服务器根据返回的结果处理自己的业务;
⑦java后端处理后自己的业务后,将验证结果以及自己所要返回的内容返回给app端;
②app端在请求苹果系统服务器检查java服务端服务是否已经验证;
③苹果服务告知app端,java服务是否验证成功;
⑧app端根据苹果服务器返回的验证结果通知提示用户订单是否结束;

注:苹果支付内购,价格是以6的倍数定价,且产品订单是唯一的;

三.java代码

①调用验证工具类校验app端返回的结果是否正确

 /**
     * TransactionID:苹果配置的产品id
     * String receipt_data:需要客户端传过来的参数2
     * 苹果内购支付
     *
     * @Title: doIosRequest
     * @Description:Ios客户端内购支付
     */
    @RequestMapping("/applePay")
    public Result doIosRequest(HttpServletRequest request, @RequestBody ApplePayVo applePayVo) {
        Result ext = new Result();
        String receipt_data = applePayVo.getReceipt_data();
        String transactionID = applePayVo.getTransaction_id();
        String verifyResult = iosVerifyUtil.buyAppVerify(receipt_data,applePayVo.getType());
             //苹果服务器没有返回验证结果
            if (verifyResult == null) {
                JSONObject jsonObject= new JSONObject();
                jsonObject.put("verify_status",-1);
                ext.setData(jsonObject);
                ext.setMessage("无订单信息!");
                ext.setCode(-1);
                return ext;
            } else {
                // 苹果验证有返回结果
                //log.info("线上,苹果平台返回JSON:" + verifyResult);
                JSONObject job = JSONObject.parseObject(verifyResult);
                String states = job.getString("status");
                //获取苹果系统服务器验证结果数据处理自己的业务
                Result appPay = applePayService.getAppPay(states, job, transactionID, request, applePayVo);
                return appPay;
            }
        }

②获取验证后的数据处理自己的业务逻辑

 /**
     * 苹果支付验证后
     **/
    public Result getAppPay(String states, JSONObject job, String transactionID, HttpServletRequest request, ApplePayVo applePayVo) {
        Result ext = new Result();
        //log.info("苹果平台返回值:job" + job);
        //判断是否验证成功
        if ("0".equals(states)) {
            //app端所提供的收据是有效的    验证成功
            String r_receipt = job.getString("receipt");
            JSONObject returnJson = JSONObject.parseObject(r_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");
            //产品id
            String productId = in_appJson.getString("product_id");
            //苹果支付订单状态
            String in_app_ownership_type = in_appJson.getString("in_app_ownership_type");
            //如果获取验证后的支付订单单号与app端传来的支付订单号一致并且状态为已支付状态则处理自己的业务
            if (transactionID.equals(transactionId) && in_app_ownership_type.equals("PURCHASED")) {
            ===================处理自己的业务============================
        }
}
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("verify_status", -1);
        ext.setMessage("receipt数据有问题");
        ext.setData(jsonObject);
        ext.setCode(-1);
        return ext;
}

③发送苹果系统服务器支付结果验证工具类

package com.asftek.pay.common.utils;

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 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;
        }
    }

    @Value("${applepay.verifyUrl}")
    private  String url_apple_pay;

    @Value("${applepay.verifyTestUrl}")
    private  String test_url_apple_pay;


    /**
     * 苹果服务器验证
     *
     * @param receipt 账单
     * @return null 或返回结果 沙盒 https://sandbox.itunes.apple.com/verifyReceipt
     * @url 要验证的地址
     */
    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;

    }
}

④java调用验证后苹果系统服务器返回参数
 

新版IOS返回(7.0以后)
{
    "receipt": {
        "receipt_type": "ProductionSandbox",
        "adam_id": 0,
        "app_item_id": 0,
        "bundle_id": "com.xxxx.xxxx",
        "application_version": "1",
        "download_id": 0,
        "version_external_identifier": 0,
        "receipt_creation_date": "2021-11-01 09:20:51 Etc/GMT",
        "receipt_creation_date_ms": "1635758451000",
        "receipt_creation_date_pst": "2021-11-01 02:20:51 America/Los_Angeles",
        "request_date": "2021-11-01 09:20:52 Etc/GMT",
        "request_date_ms": "1635758452973",
        "request_date_pst": "2021-11-01 02:20:52 America/Los_Angeles",
        "original_purchase_date": "2013-08-01 07:00:00 Etc/GMT",
        "original_purchase_date_ms": "1375340400000",
        "original_purchase_date_pst": "2013-08-01 00:00:00 America/Los_Angeles",
        "original_application_version": "1.0",
        "in_app": [{
            "quantity": "1",
            "product_id": "",//唯一的
            "transaction_id": "1000000901786189",
            "original_transaction_id": "1000000901786189",
            "purchase_date": "2021-11-01 09:13:33 Etc/GMT",
            "purchase_date_ms": "1635758013000",
            "purchase_date_pst": "2021-11-01 02:13:33 America/Los_Angeles",
            "original_purchase_date": "2021-11-01 09:13:33 Etc/GMT",
            "original_purchase_date_ms": "1635758013000",
            "original_purchase_date_pst": "2021-11-01 02:13:33 America/Los_Angeles",
            "is_trial_period": "false",
            "in_app_ownership_type": "PURCHASED"
        }]
    },
    "environment": "Sandbox",
    "status": 0
}

⑤错误码

java 苹果支付(内购)_第2张图片

你可能感兴趣的:(java)