对接苹果支付流程上相较于微信或者支付宝来说 后端做的代码是非常少的 但是需要注意的点很多
对于支付 最重要的是知道这笔支付到底是不是真正意义上成交了,以及成交价格是否对应我们的商品价格 这是我们需要去判断的
苹果支付对于微信支付和支付宝支付来说,有本质的区别。苹果支付的商品需要现在appstore里面去上架。所以整个支付流程如下
APP内请求苹果SDK发起支付。并完成购买。支付成功之后APP端会传一段receipt_data(同时需要带上APP支付成功的交易单号)给后端去做验证。后端拿到这个数据之后,会再次请求苹果服务器去解析数据。
结构如下:
{
"receipt": {
"receipt_type": "ProductionSandbox",
"adam_id": 0,
"app_item_id": 0,
"bundle_id": "申请苹果支付时的串号 固定的值",
"application_version": "24",
"download_id": 0,
"version_external_identifier": 0,
"receipt_creation_date": "2022-02-18 08:02:19 Etc/GMT",
"receipt_creation_date_ms": "1645171339000",
"receipt_creation_date_pst": "2022-02-18 00:02:19 America/Los_Angeles",
"request_date": "2022-02-23 13:21:51 Etc/GMT",
"request_date_ms": "1645622511107",
"request_date_pst": "2022-02-23 05:21:51 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": "10000",
"transaction_id": "1000000972016787",
"original_transaction_id": "1000000972016787",
"purchase_date": "2022-02-18 08:02:19 Etc/GMT",
"purchase_date_ms": "1645171339000",
"purchase_date_pst": "2022-02-18 00:02:19 America/Los_Angeles",
"original_purchase_date": "2022-02-18 08:02:19 Etc/GMT",
"original_purchase_date_ms": "1645171339000",
"original_purchase_date_pst": "2022-02-18 00:02:19 America/Los_Angeles",
"is_trial_period": "false",
"in_app_ownership_type": "PURCHASED"#交易状态
},
{
"quantity": "1",
"product_id": "betterwe_camp_21",
"transaction_id": "1000000970947758",
"original_transaction_id": "1000000970947758",
"purchase_date": "2022-02-17 07:26:24 Etc/GMT",
"purchase_date_ms": "1645082784000",
"purchase_date_pst": "2022-02-16 23:26:24 America/Los_Angeles",
"original_purchase_date": "2022-02-17 07:26:24 Etc/GMT",
"original_purchase_date_ms": "1645082784000",
"original_purchase_date_pst": "2022-02-16 23:26:24 America/Los_Angeles",
"is_trial_period": "false",
"in_app_ownership_type": "PURCHASED"
},
]
},
"environment": "Sandbox",
"status": 0
}
订单总共如下几种状态
状态 | 描述 |
---|
Purchased | 购买成功 | Restored | 恢复购买 | Failed | 失败 | Deferred | 等待确认,儿童模式需要询问家长同意 |
-
app从服务器获取产品标识列表 -
app从app store 获取产品信息 -
用户选择需要购买的产品 -
app 发送 支付请求到app store -
app store 处理支付请求,返回transaction信息 -
app 将transaction receipt 发送到服务器 -
服务器收到收据后发送到app stroe验证收据的有效性 -
app store 返回收据的验证结果 -
根据app store 返回的结果决定用户是否购买成功
基本的支付校验流程如下: 下面贴上具体的业务逻辑代码
public function actionsApplepay($receipt_data, $order_number, $transaction_id, $order_info, $is_test){
$ret = array();
$ret['status'] = 200;
$ret['msg'] = "ok";
try{
(new Order())::updateAppleOrderIsPaying($order_number);
if ($is_test == 1) {
$url = "https://sandbox.itunes.apple.com/verifyReceipt";
}else{
$url = "https://buy.itunes.apple.com/verifyReceipt";
}
$receipt_data = str_replace(' ',"+", $receipt_data);
$post_data = json_encode(array("receipt-data" => $receipt_data));
$response = https_request($url, $post_data);
$res = json_decode($response, true);
$err_msg = array(
'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(intval($res['status']) === 0){
if($res['receipt']['bundle_id'] != 'com.wegymer.betterwestar'){
throw new Exception('非法请求!', -1);
}
$pay_status = false;
if(count($res['receipt']['in_app'])){
foreach ($res['receipt']['in_app'] as $apple_order){
if($apple_order['product_id'] == $order_info['goods_id'] && $apple_order['transaction_id'] == $transaction_id && $apple_order['in_app_ownership_type'] == 'PURCHASED'){
$pay_status = true;
}
}
}
if($pay_status == true){
$update_order_info_res = (new Order())->updateOrderIsPaySuccess($order_number, 3, $transaction_id);
if($update_order_info_res['status'] != 200){
throw new Exception($update_order_info_res['msg'], $update_order_info_res['status']);
}
}else{
throw new Exception('未查询到当前订单的支付成功记录', -3);
}
}else{
if($res['status'] == 21007){
$update_order_info_res = (new Order())->updateOrderIsPaySuccess($order_number, 3, 'XXXXXXXXXX-SANDBOX');
if($update_order_info_res['status'] != 200){
throw new Exception($update_order_info_res['msg'], $update_order_info_res['status']);
}
}else{
(new Order())::recordOrderErrorLog($order_number, '购买失败 status:'.$res['status'].' - '.@$err_msg[$res['status']].'receipt_data:'.$receipt_data);
throw new Exception('购买失败 status:'.$res['status'].' - '.@$err_msg[$res['status']], $res['status']);
}
}
}catch (Exception $e) {
(new Order())::updateAppleOrderIsNoPaying($order_number);
$ret['status'] = $e->getCode();
$ret['msg'] = $e->getMessage();
}
return $ret;
}
```
上面为具体的业务逻辑代码
|