IAP 自动续费后端接入指南

前言

iap自动续费在线上运行了比较久的时间了, 相对稳定, 最开始开发的时候, 没有找到一个比较完备的server端开发指南, 所以在此做一个记录, 希望可以帮助到更多的人快速搭建自己的server端程序

使用场景

我们的场景是一个连包会员业务, ios端使用iap的自动续期订阅类型

接入流程

1. 后台配置

后台配置比较简单, 不在此赘述, 不会的可以参考https://www.jianshu.com/p/9e64449807ff 这片帖子

2. 方案选择

查看apple文档后, 总结出自动续费一共有三种

  1. 客户端主动上报, apple每期自动扣款后, 会生成一笔新的receipt, 客户端获取后发送给server校验, 成功后开通下一期会员权益

  2. 状态变更通知 用于自动续订订阅的服务器到服务器通知服务, 可以在苹果后台配置通知地址, 状态变更时, server会收到通知, 下面是摘自苹果官方的状态描述

NOTIFICATION_TYPE描述
INITIAL_BUY初次购买订阅。latest_receipt通过在App Store中验证,可以随时将您的服务器存储在服务器上以验证用户的订阅状态。
CANCELApple客户支持取消了订阅。检查Cancellation Date以了解订阅取消的日期和时间。
RENEWAL已过期订阅的自动续订成功。检查Subscription Expiration Date以确定下一个续订日期和时间。
INTERACTIVE_RENEWAL客户通过使用应用程序界面或在App Store中的App Store中以交互方式续订订阅。服务立即可用。
DID_CHANGE_RENEWAL_PREF客户更改了在下次续订时生效的计划。当前的有效计划不受影响。

详情可以查看https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Chapters/Subscriptions.html#//apple_ref/doc/uid/TP40008267-CH7-SW13

  1. server轮询 自动续订类型的收据, 每一期的latest_receipt_info中都会记录所有的交易(包含历史和新增), 可以轮询上一期(任意一期都可以)receipt, 通过latest_receipt_info 解析出用户最新的订阅状态.
    在这里插入图片描述
    具体的收据内容可以查看https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW2
三种方案的对比
方案优势缺点
客户端主动上报首次购买收据只能通过这种方式获取1.续费收据需要用户打开app才会上传, 时效性不够好 2.无法获取关闭订阅的行为
状态变更通知可以获取到用户取消订阅的消息(退款)1.不够可靠, 可能会丢失通知(看大家评论得出, 并未亲自尝试) 2.无法获取关闭订阅的行为
server轮询只要发起轮询, 就可以随时获取用户的订阅状态(续费, 退款, 关闭)1.无法获取首次购买收据 2.成本较高, 需要对历史收据进行轮询
最终方案

分析了上述3种方案后, 我们决定将3种方案结合, 来实现我们的iap自动续费处理流程

  1. 使用 server轮询, 每次使用用户上一期的receipt调用apple的校验接口, 调用时机有两处:
    a.当期订阅结束时间前一天, 获取用户是否续费成功(只获取续费成功的状态, 退款和关闭对时效性要求较高)
    b.用户访问会员首页时进行查询, 及时获取用户订阅的关闭状态(用户在ituns中关闭订阅后, 我们app需要同步更新订阅状态, 所以在用户进入会员首页时进行查询, 如果延迟过久, 用户会抓狂的)
  2. 接收 客户端主动上报, 获取用户切换订阅商品的行为
  3. 接收 状态变更通知 , 获取用户的退款行为, 属于逆向逻辑, 与正向的轮询任务放在一起, 耦合过高, 所以放在回调通知中处理.

3.关键点

3.1 续费表扣费状态的设计

等待扣费, 上一期扣费成功且这一期还未明确扣费状态(成功, 关闭, 失败), 轮询时会查到该数据
扣费成功 , 扣费成功,轮询时不会查到该数据
扣费失败 , 对于扣费失败的用户, 苹果仍会尝试扣款60天, 此时应该标记为扣费失败, 轮询时会查到该数据
已关闭, 订阅已经关闭, 不会再次扣费, 轮询时不会查到该数据

3.2 如何判断用户续费成功?

解析出 latest_receipt_info 中最新的一笔交易, 使用 expires_date_ms (过期时间)与当前时间作比较, 如果 expires_date_ms >当前时间, 则续费成功

3.3 如何判断用户关闭订阅?

解析 pending_renewal_info , 该字段是续订状态的说明. auto_renew_status 为0, 说明已经关闭订阅.

3.4 如何判断苹果扣费失败?

对于扣费失败的用户, 苹果仍会尝试扣款60天, 解析 pending_renewal_info , auto_renew_status 为1并且 is_in_billing_retry_period 为1, 此时用户的状态并不能标记为已关闭, 而应该是扣费失败

3.5 如何判断用户在订阅周期内切换商品?

解析 pending_renewal_info, 取 product_id 字段, 此字段为最新一期续订的商品, 一定不要取 auto_renew_product_id 字段, 这是个大坑

3.6 如何判断用户已退款?

有两种方式:
a. 解析latest_receipt_info中的交易, 退款后会出现cancellation_date和cancellation_reason字段, 未退款则没有这两个字段
b. 接收 状态变更通知, 当 notification_typeCANCEL 时表明已退款, 此时再解析出 latest_expired_receipt_info 中的 transaction_id 即可与内部订单关联进行退款

3.7 server轮询时查哪些数据?

查询两类数据:
a. 状态为 等待扣费 并且 当前周期结束时间在当前时间之后一天的记录, 苹果会在订阅到期之前的24小时内发起扣款, 所以只查询这段时间内的数据就可以, 减少无用的轮询
b. 所有状态为 扣费失败 的记录

3.8关于幂等性校验和restore问题

由于receipt可以多次查询, 返回相同结果, 在我们每次处理前, 需要判断交易是否已经处理过, 已处理过则不再处理, restore时, 同一笔交易会重新生成transactionId, 所以我们校验的唯一key应该是, original_transaction_id(用户唯一标识)+purchase_date_ms(订阅周期开始时间)+expires_date_ms(订阅周期结束时间)

3.9 用户切换相同周期产品退款问题

当用户切换了同一group下、周期相同的产品时(比如两个连续包月切换), 苹果会将上一笔交易退款, 此处可能会成为一个刷单漏洞(用户不断切换appId, 进行切换商品操作)需要注意一下这一点. 目前我的处理方案是, 用户进首页轮询时倒序查找三条交易, 看是否退款, 未处理过的退款进行退款操作, 回收会员权益

3.10 如何判断首单优惠?

解析交易中的is_in_intro_offer_period字段, 为true时表示享受了介绍性价格

3.11 如何判断免费试用?

解析交易中的is_trial_period字段, 为true表示享受了免费试用

最后

有疑问的地方欢迎大家加我qq 790742549 进行交流

  • 15
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值