开发日记 —— 苹果支付指南
目录
上一篇文章分享了实践 Apple 登录的开发过程。 今天主要分享一下 Apple 支付的实践。
前言 #
本次实践中,笔者采用了 订阅 + 一次性付费 的模式。用户可根据自己的需求,选择会员订阅周期。从大部分开发者角度来说,订阅模式是比较常见的,因为订阅更有力于APP的长期发展。
购买项配置 #
进入 开发者后台配置
-
在 App 内购买项目 中创建 永久会员
-
在 订阅 创建订阅组,后分别 月度会员 年度会员
需要注意两点:
- 创建的购买项需要设置多语言,否则会出现报错 缺少元数据。
- 审核信息的截图有设备尺寸限制,可参考官方文档:
https://developer.apple.com/help/app-store-connect/reference/screenshot-specifications
客户端 #
我使用 in_app_purchase 插件,在客户端进行支付。可以运行插件的example进行测试。成功运行效果如下:
具体细节可以参考插件文档,需要注意的是,我们需要如何进行iOS订单的验证。 通过插件的demo我们看到默认返回true,所以这部分逻辑需要开发者自己实现。
Future<bool> _verifyPurchase(PurchaseDetails purchaseDetails) async {
// IMPORTANT!! Always verify a purchase before delivering the product.
// For the purpose of an example, we directly return true.
return Future<bool>.value(true);
}
通过方法返回的类型可以得到:
class PurchaseVerificationData {
/// ...
/// The data used for local verification.
///
/// The data is formatted according to the specifications of the respective
/// store. You can use the [source] field to determine the store from which
/// the data originated and proces the data accordingly.
final String localVerificationData;
/// The data used for server verification.
final String serverVerificationData;
}
我们看到 localVerificationData 用于本地验证,serverVerificationData 用于服务器验证。
final verificationData =
purchaseDetails.verificationData.serverVerificationData;
final Dio dio = Dio();
dio.options.headers['Accept'] = 'application/json';
dio.options.headers['Content-Type'] = 'application/json';
var response = await dio.post('https://buy.itunes.apple.com/verifyReceipt',
data: {
'password': password,
'receipt-data': verificationData
});
var _response = json.decode(response.toString());
if (_response["status"] == 21007) {
var response = await dio
.post('https://sandbox.itunes.apple.com/verifyReceipt', data: {
'password': password,
'receipt-data': verificationData
});
}
if (_response["status"] == 0) {
return Future<bool>.value(true);
} else {
return Future<bool>.value(false);
}
以前苹果提供了一个验证接口,可以跳过服务端进行验证,可惜在去年5月份被标记 Deprecated(已弃用)
,虽然目前看来还是可以使用,但是保不齐哪天就被苹果给删掉了。
通过文档我们得知:
该接口已弃用。要验证服务器上的收据,请按照在服务器上的设备上验证收据中的步骤操作。要在不使用收据的情况下验证服务器上的应用内购买,请调用App Store Server API为您的客户获取 Apple 签名的交易和订阅信息,或验证您的应用获取的签名数据。您还可以从App Store Server Notifications V2端点获取相同的签名交易和订阅信息 。
所以需要改用 App Store Server API 进行验证。
获取交易信息 #
https://developer.apple.com/documentation/appstoreserverapi/get_transaction_info
根据文档的描述,我们得知此接口我们可以获取 包含签名的单个交易信息的结果。
接着,通过苹果开发后台进行配置下载 私钥匙文件 + KeyID + BundleID + Issuer 进行验签比对订单号等数据判断交易是否成功。
获取历史交易信息 #
https://developer.apple.com/documentation/appstoreserverapi/get_transaction_history
根据此接口我们可以获取包含签名的多个交易信息的结果,同样验签后获取详细数据。
我们可以通过此接口进行订阅到期续费情况等数据进行判断。
验签及API配置 #
在此页面我们可以获取验签需要的数据 私钥匙文件、 KeyID + BundleID + Issuer
创建沙盒账号后可进行购买订阅的测试,不会收取费用。
内购被拒 #
另外,在完成所有工作发布可能会被拒,因为我之前没有订阅经验,所以遇到了一些问题。
如果做了订阅我建议你完成以下步骤,如果这些步骤都做到了,那么大概率是不会被拒的。
- 在付费页面提供隐私政策及使用条款的入口。
- 在使用条款中明确说明和介绍你的订阅服务,包含的服务内容、订阅周期、退订、取消订阅等信息。
- 在APP详情页中,提供订阅服务的详细说明。
- 提供恢复购买的功能。
如果还是不知道如何做,可以参考一些其他的APP,一般在他们的App详情页和使用条款中都有订阅相关的说明。
总结 #
理论上来说,获取交易信息 获取历史交易信息 这两个接口的数据都可以放在客户端本地调用,只是验证这一步放在服务端去做比较符合逻辑。
无论是全部交易接口在服务端还是验签在服务端,都可能被劫持,即在返回客户端前,对数据进行加工处理,比如修改交易状态来欺瞒客户端。
所以,最好是对接口数据进行加密。我采用对请求参数返回结构进行 AES 加密,及时数据被劫持也无法进行修改。
如果没有服务端,极端的方式是把验签放在客户端进行能跑通,因安全性问题不推荐这么做。