苹果应用内支付(IAP)的测试对接是iOS应用上线前的重要验证环节,使用PHP作为服务端语言时,需要按照苹果官方的规范完成测试账号配置、凭证校验等流程,确保支付功能在正式环境前能正常运行。

前期准备
在开始对接前,需要先完成以下基础配置:
- 拥有苹果开发者账号,且已创建对应的App ID并开启应用内购买功能
- 在苹果开发者后台的
用户和访问模块中,创建沙箱测试账号,测试账号需要使用未注册过苹果服务的邮箱,密码需符合苹果复杂度要求 - 在应用的Xcode项目中,开启
Capabilities中的应用内购买开关,并配置对应的商品ID - 准备PHP运行环境,确保支持cURL扩展,用于调用苹果验证接口
测试环境配置
苹果支付分为正式环境和沙箱测试环境,对接测试账号时需要切换到沙箱环境:
- iOS设备退出当前登录的正式Apple ID,在设置中登录沙箱测试账号
- 应用内发起支付时,会自动走沙箱支付通道,支付时不会扣除真实费用
- 苹果沙箱验证接口地址为:
https://sandbox.itunes.apple.com/verifyReceipt,正式环境地址为https://buy.itunes.apple.com/verifyReceipt,测试阶段需使用沙箱地址
PHP对接核心实现
1. 获取支付凭证
iOS端完成支付后,会返回支付凭证receipt-data,需要将这个凭证传递给PHP服务端进行校验,凭证是Base64编码的字符串。
2. PHP验证凭证代码实现
服务端需要把凭证和共享密钥(在苹果开发者后台的应用内购买模块获取)一起发送到苹果验证接口,解析返回结果判断支付是否有效。
<?php
/**
* 苹果支付测试账号凭证验证方法
* @param string $receiptData iOS端传递的Base64编码支付凭证
* @param string $sharedSecret 苹果开发者后台的共享密钥
* @param bool $isSandbox 是否为沙箱测试环境,测试阶段传true
* @return array 验证结果数组
*/
function verifyApplePayReceipt($receiptData, $sharedSecret, $isSandbox = true) {
// 选择验证接口地址,测试环境用沙箱地址
if ($isSandbox) {
$verifyUrl = 'https://sandbox.itunes.apple.com/verifyReceipt';
} else {
$verifyUrl = 'https://buy.itunes.apple.com/verifyReceipt';
}
// 构造请求参数
$postData = json_encode([
'receipt-data' => $receiptData,
'password' => $sharedSecret,
'exclude-old-transactions' => true
]);
// 初始化cURL
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $verifyUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
// 关闭SSL证书验证,测试环境可临时关闭,正式环境建议开启
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
// 执行请求
$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
return [
'success' => false,
'message' => '请求苹果接口失败:' . $error
];
}
// 解析返回结果
$result = json_decode($response, true);
// 状态码21007表示凭证是沙箱环境的,但请求了正式接口,自动切换到沙箱地址重试
if (isset($result['status']) && $result['status'] == 21007 && !$isSandbox) {
return verifyApplePayReceipt($receiptData, $sharedSecret, true);
}
// 状态0表示验证成功
if (isset($result['status']) && $result['status'] == 0) {
return [
'success' => true,
'data' => $result['receipt'],
'message' => '支付凭证验证成功'
];
} else {
return [
'success' => false,
'data' => $result,
'message' => '支付凭证验证失败,状态码:' . ($result['status'] ?? '未知')
];
}
}
// 调用示例,实际使用时从iOS端请求参数中获取对应值
$receiptData = 'iOS端传递的Base64凭证字符串';
$sharedSecret = '你的苹果开发者后台共享密钥';
$verifyResult = verifyApplePayReceipt($receiptData, $sharedSecret, true);
if ($verifyResult['success']) {
// 验证成功,处理业务逻辑,比如给用户发放商品、更新订单状态
echo '支付验证通过,开始发放商品';
} else {
// 验证失败,记录日志并返回错误提示
echo '支付验证失败:' . $verifyResult['message'];
}
?>
常见问题排查
- 验证返回状态码21002:通常是
receipt-data格式错误,检查iOS端是否正确传递了Base64编码的凭证,不要额外添加换行或空格 - 验证返回状态码21003:可能是共享密钥错误,检查开发者后台的共享密钥是否复制正确,注意不要有多余的空格
- 测试账号无法支付:检查iOS设备是否登录了沙箱测试账号,且测试账号没有被锁定,可在开发者后台重置测试账号密码
- 凭证验证一直失败:确认请求的是沙箱接口,测试阶段不要使用正式环境接口地址
注意事项
测试完成后上线正式环境时,需要把验证接口地址切换到正式地址,同时关闭cURL的SSL证书跳过配置,确保请求的安全性。另外苹果支付的凭证具有唯一性,需要做好幂等处理,避免重复发放商品。