苹果的官方支付文档比较详细,但如果想要在短时间内接入好完整流程,也是有一定难度的。
好在有一些勤劳的人已经为我们完成了艰苦的工作——Laravel In-App purchase。
使用 Laravel In-App purchase 这个扩展包,可以很轻松接入苹果支付。
安装
通过 Composer 安装:
1 | $ composer require imdhemy/laravel-purchases |
发布配置文件:
1 | $ php artisan liap:config:publish |
config/liap.php
将创建一个包含以下配置键的文件,核心配置项如下:
routing
: 允许添加自定义路由配置google_play_package_name
: Google Play 包名称appstore_password
: App Store 共享密钥,下面会介绍如何获取eventListeners
: 事件列表
仅当需要从App Store请求测试通知时,才需要以下键:
appstore_private_key_id
:来自 App Store 连接的私钥 ID(例如:2X9R4HXF34)appstore_private_key
:私钥文件的路径(例如:/path/to/SuperSecretKey_ABC123.p8)appstore_issuer_id
:App Store Connect 中“密钥”页面中的颁发者 ID(例如:57246542-96fe-1a63-e053-0824d011072a)appstore_bundle_id
:应用程序的捆绑 ID(例如:com.example.testbundleid2021)
创建销售产品
根据实际情况,选择创建对应类型的销售产品,订阅、消耗品还是非消耗品。
要在应用内提供应用内购买,需要先在 App Store Connect 中添加其信息:
- 前往App Store Connect
- 从我的应用程序中,选择应用程序
- 在侧边栏中的功能下,选择应用内购买
- 单击添加按钮 (+)
- 选择消耗品、非消耗品、还是订阅
- 通过添加参考名称和产品 ID 来填写表格
- 单击创建按钮
获取 App Store 凭证
请求 App Store Api 时,需要用到 App-Specific Share Secret,通过以下方式获取:
- 前往App Store Connect
- 找到我的应用程序并选择要配置的应用程序
- 从左侧菜单“常规”部分下选择应用程序信息
- 从右侧的“应用程序特定共享密钥”部分下选择“管理”
- 生成并复制共享秘密
支付流程
支付流程:
- App 从 App Store 获取产品信息
- 用户选择需要购买/订阅的产品
- App 发送支付请求到 App Store
- App Store 处理支付请求,返回 transaction 信息
- App 将transaction receipt 发送到服务器
- 服务器收到收据后,发送到 App Stroe 验证收据的有效性
- App store 返回收据的验证结果
- 根据 App store 返回的结果,决定用户是否购买成功
流程图如下:
这个支付流程和一些主流的支付流程不一样,传统的支付流程是在服务端发起支付,然后通过回调确认是否支付成功。
而 In-App purchase 的核心支付流程是由,客户端发起支付,然后再由服务端去确认是否支付成功。
上面流程中,大部分都是 App 上的逻辑,就不在此过多介绍。
验证订单信息
从第六步开始,才与服务端有关,需要由服务端,向 App Store 发起验证。
1 | use Imdhemy\Purchases\Facades\Subscription; |
App 那边会从 Apple 那边拿到一个 receiptData 收据,这个收据用于向App Store,验证订单信息,是否有效。
通知
除了处理收据问题,另外一个比较重要的就是通知了。
当订阅过期时,会发送过期对应的事件、当用户重新续订时,会发送续订事件、当订阅状态发生变化时,也会发送对应事件。
常用的订阅事件及子事件:
- SUBSCRIBED:订阅成功
- INITIAL_BUY: 首次购买
- RESUBSCRIBE: 重新订阅
- DID_RENEW: 订阅续订
- BILLING_RECOVERY:之前未能续订的过期订阅已成功续订
- : 活动订阅已成功自动续订新的交易期
- DID_CHANGE_RENEWAL_STATUS: 订阅状态变更
- AUTO_RENEW_ENABLED: 重新启用订阅自动续订
- AUTO_RENEW_DISABLED: 禁用了订阅自动续订
- EXPIRED: 订阅过期
- VOLUNTARY: 订阅在用户禁用订阅续订后过期
- BILLING_RETRY: 订阅过期,因为计费重试期结束,账单交易没有成功
- PRICE_INCREASE: 订阅过期,因为用户不同意需要用户同意的价格上涨
- PRODUCT_NOT_FOR_SALE: 订阅过期,因为在订阅尝试续订时,该产品无法购买
如果要查看更多的订阅事件,可以查看App Store 订阅事件列表。
1 |
|
正常解析出来,可以得到以下信息:
1 | { |
关于字段完整解释,可以查看 Transaction data types。
配置通知地址
Laravel In-App purchase 提供 URL 在 App Store Connect / Google Play 中设置服务器通知地址。
- 使用
php artisan liap:url
命令,可以通过routing.signed
配置选择是否需要带有签名的 URL:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16$ php artisan liap:url
Select provider:
[0] All Providers
[1] App Store
[2] Google Play
> 0
Signed routes are disabled. Do you want to generate signed routes? (yes/no) [no]:
> yes
+-------------+--------------------------------------------------------------------------------+
| Provider | URL |
+-------------+--------------------------------------------------------------------------------+
| App Store | http://localhost/liap/notifications?signature=<signature>&provider=app-store |
| Google Play | http://localhost/liap/notifications?signature=<signature>&provider=google-play |
+-------------+--------------------------------------------------------------------------------+
签名用于验证,请求是否合法。
- 登录App Store Connect并选择应用程序
- 在应用程序信息 > 应用程序商店服务器通知部分下,将通知 URL 粘贴到生产服务器 URL和 沙盒服务器 URL字段中
- 在版本字段中选择版本
1
或2
版本不同,会导致通知类型有所不一样,完整的 notificationType 可以查看苹果开发者文档。
关于苹果支付,因为跟传统的支付流程不太一样,内容还是挺多的,暂时只用到订阅部分,后面有其他的内容再补充。