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//官网状态码
一.苹果支付
①逻辑流程图
二,苹果支付流程介绍
①户在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
- }
复制代码 ⑤错误码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |