这里写目录标题
一,苹果内购流程
1. 选择商品或服务
通过接口获取商品或服务列表
注意 product_id 需要根据app store
定义填写(非平台内商品/服务的ID)
这里需要后端提供商品/服务列表接口, 前端处理用户操作逻辑
2. 确认支付并调用接口创建订单记录
调起支付前向后端发送创建订单记录请求
后面验证支付结果需要订单信息
3. 调起APP内苹果支付并进行购买支付流程
已经调起了苹果支付由用户完成操作
4. 向服务器发起验证凭证以及支付结果的请求
最后拿到用户操作后返回
receipt
票据字段和订单号提交给后端接口处理验证
返回code: 0
则为验证成功
二,验证返回的状态码
验证返回的状态码
0 验证成功
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环境的验证服务
三,服务端处理
1. 创建订单记录
/**
* IOS创建订单
*/
public function iosCreateOrder()
{
// 参数
$params = [
'product_id' => 1,
];
// 处理订单所需数据组合
$data = [];
// 处理创建订单逻辑
// 调用模型创建订单
// 返回订单号
return [
'order_number' => $data['order_number'],
];
}
2. 验证票据
/**
* 苹果订单验证
* 验证返回的状态码
* 0 验证成功
* 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环境的验证服务
*/
public function iosVerify()
{
// 包名
$bundleId = '';
$receipt = ''; // 票据
$orderNumber = ''; // 当前交易单号
// 返回信息定义
$resultMsg = [
'code' => 400,
'message' => '支付验证失败',
];
// 验证票据结果
$result = $this->iosVerifyTickets($receipt);
// 沙盒模式
if ($result['status'] == 21007) {
$result = $this->iosVerifyTickets($receipt, true);
}
if (!is_array($result)) {//大概率是超时
$resultMsg['code'] = 403;
}
if ($result['status'] == 0) {//验证成功
if ($result['receipt']['bundle_id'] != $bundleId) {
// 包名验证错误
$resultMsg['message'] = 'APP_KEY 验证错误';
$resultMsg['code'] = 401;
}
//当订购一个套餐后再次订购此套餐可能会出现这种情况,非常规操作
if (empty($transaction)) {
$resultMsg['code'] = 402;
}
// 开启事务
try {
// 更新订单信息
// 提交事务
} catch (Exception $e) {
// 事务回退
}
} else {
$resultMsg['code'] = 400;
}
return response()->json($resultMsg);
}
/**
* ios验证票据
* @param string $receipt
* @param false $sandbox
* @return array|int|mixed
* @throws Exception
*/
protected function iosVerifyTickets(string $receipt, bool $sandbox = false)
{
if ($sandbox) {
$url = 'https://sandbox.itunes.apple.com/verifyReceipt'; // 测试环境
} else {
$url = 'https://buy.itunes.apple.com/verifyReceipt'; // 正式环境
}
$params = json_encode(array("receipt-data" => $receipt));
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
$data = curl_exec($curl);
$errno = curl_errno($curl);
curl_close($curl);
$data = json_decode($data, true);
if (!is_array($data)) { // 开发过程中经常遇到curl 35错误码,或者28超时
return $errno;
}
return $data;
}