IAP 自动续费后端接入指南

IAP 自动续费后端接入指南

  • 前言
    • 使用场景
    • 接入流程
      • 1. 后台配置
      • 2. 方案选择
          • 三种方案的对比
          • 最终方案
      • 3.关键点
        • 3.1 续费表扣费状态的设计
        • 3.2 如何判断用户续费成功?
        • 3.3 如何判断用户关闭订阅?
        • 3.4 如何判断苹果扣费失败?
        • 3.5 如何判断用户在订阅周期内切换商品?
        • 3.6 如何判断用户已退款?
        • 3.7 server轮询时查哪些数据?
        • 3.8关于幂等性校验和restore问题
        • 3.9 用户切换相同周期产品退款问题
        • 3.10 如何判断首单优惠?
        • 3.11 如何判断免费试用?
  • 最后

前言

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 进行交流

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/52109.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微信代扣踩坑日记(微信自动续费)

1.背景 最近接到一个产品支付功能,要求打通微信自动续费功能,类似腾讯视频的会员自动续费。原计划开发周期为一周左右,由于微信坑爹的接口文档以及蛋疼的审核程序,导致前后将近耗时近一个月,支付方式也是从支付中签约换…

后端做app连续会员包月功能 -- IOS连续订阅 支付宝周期扣款

IOS连续订阅总结 如何判断后续用户是续费 1. 服务端轮询续费表,会员到期的前一天,根据用户id。去苹果服务器检验用户是否续费成功a. 查询的状态应有:等待扣费、扣费失败b. 扣费失败 , 对于扣费失败的用户, 苹果仍会尝试扣款60天, 此时应该标…

Stripe订阅模式(类似于会员,按月按年自动扣款)

文章目录 stripe订阅模式与普通支付模式的区别支付成功回调支付失败回调订阅生命周期 一、区别 创建stripe订单时(支付接口)的区别: 1.普通订阅模式创建session前需要先创建价格对象,订阅需要在价格对象中多添加一个recurringPar…

论文投稿指南——中文核心期刊推荐(新闻事业)

【前言】 🚀 想发论文怎么办?手把手教你论文如何投稿!那么,首先要搞懂投稿目标——论文期刊 🎄 在期刊论文的分布中,存在一种普遍现象:即对于某一特定的学科或专业来说,少数期刊所含…

论文投稿指南——中文核心期刊推荐(社会学)

【前言】 🚀 想发论文怎么办?手把手教你论文如何投稿!那么,首先要搞懂投稿目标——论文期刊 🎄 在期刊论文的分布中,存在一种普遍现象:即对于某一特定的学科或专业来说,少数期刊所含…

想用Python赚钱?——安排!

利用Python进行网络抓取,本文会告诉你最显而易见的赚钱办法,还有隐藏的最不明显的赚钱方法。 数据是一种非常有用的资源。有人甚至称数据为21世纪的石油。 这就是为什么不仅是公司,而且普通人也会花钱在电子表格中获得干净的数据,…

微信小程序数据请求

微信小程序的数据请求 一、常用的数据请求方式 JS原生实现 第一种:let xhrnew XMLHttpRequest()xhr.open()xhr.send()第二种:fetch() 支持promisefetch(接口地址).then(function(response) {return response.json();}).then(function(myJson) {consol…

如何用Stata完成(shui)一篇经济学论文(十一):分组和去重

文章目录 分组去重 不出意外的话,这应该是stata有关数据处理的最后一篇。emmm,其实我一开始只打算写数据处理部分的stata教程,因为我觉得对于我来说,数据处理才是最头疼的部分。不过关于后面回归,还是有些东西想跟大家…

卷积神经网络之父的强人工智能路线图:自监督,推理,规划

导读 2023 年 6 月 9 日,智源大会第一天。在这场众星云集的盛会中。目前「深度学习三驾马车」中最活跃的 Yann LeCun 教授带来了重磅演讲「朝向能学习, 思考和计划的机器进发( Towards Machines that can Learn, Reason, and Plan&#xff09…

双色球彩票训练任务含对比

玩法规则:“双色球”每注投注号码由 6 个红色球号码和 1 个蓝色球号码 组成。红色球号码从 1—33 中选择,蓝色球号码从 1—16 中选择。 package section_6_1008;import java.util.Random; import java.util.Scanner;public class section_6_1008 {publ…

一文读懂 OpenAI 创始人的「世界币」

作者 | 美漪 大概所有人,都曾经有这样一个梦想:「啥也不干,天天躺着就有人给发钱。」 现在,这个从各种角度看起来都是绝对的「白日梦」,真的有机会实现了。 当地时间 7 月 24 日,OpenAI 掌门人 Sam Altman …

书中自有黄金屋系列9:值得反复阅读的一本书《向上生长》

如果要说哪一本书对我影响最大,那肯定是这本我反复读了五遍以上九边写的《向上生长》了。很多深刻的人生道理被作者用通俗易懂的方式讲解说明,这才是最发人深省的。下面是我读书的一些笔记和思考: 1.人为什么要学习 就像人不吃饭就会死亡&…

Gavin老师Transformer直播课感悟 - Rasa对话机器人项目实战之保险行业Insurance Bot架构设计、流程分析、状态管理及智能对话实验剖析(五十五)

本文继续围绕工业级业务对话平台和框架Rasa,对Rasa对话机器人项目实战之保险行业Insurance Bot架构设计、流程分析、状态管理及基于Rasa Interactive的智能对话实验进行分析。 一、Rasa对话机器人项目实战之保险行业Insurance Bot架构设计、流程分析、状态管理及基于Rasa Inte…

GPT3.5之模仿例子完成任务

首先导入open_ai key import openai import os from dotenv import load_dotenv, find_dotenv # 导入第三方库_ load_dotenv(find_dotenv()) # 读取系统中的环境变量openai.api_key os.getenv(OPENAI_API_KEY) # path1.api_key os.getenv(path) print(openai.api_key) # p…

与 ChatGPT 进行有效交互的几种策略

在这篇文章中,您将了解即时工程。尤其, 如何在提示中提供对响应影响最大的信息什么是角色、正面和负面提示、零样本提示等如何迭代使用提示来利用 ChatGPT 的对话性质 废话不多说直接开始吧!!! 提示原则 快速工程是有…

随机森林(Random Forest)通俗教程

目录 1 什么是随机森林?2 随机森林的特点3 随机森林的相关基础知识4 随机森林的生成5 袋外错误率(oob error)6 随机森林工作原理解释的一个简单例子7 随机森林的Python实现8 参考内容 1 什么是随机森林? 作为新兴起的、高度灵活的…

加密流量分类-论文9:DarknetSec: A novel self-attentive deep learning method for darknet traffic.....

加密流量分类-论文9:DarknetSec: A novel self-attentive deep learning method for darknet traffic classification and application identification 0、摘要1、文章核心观点引入2、模型结构2.1 模型总览2.2 预处理层2.4 特征提取层 4、实验5、总结与思考 0、摘要…

陌陌X-SIGN算法HOOK

文章目录 前言应用到的工具java 层分析frida hook aesEncode,a,sign 这三个方法总结预告: 下章节我们讲:陌陌X-SIGN还原 前言 学习是必然的,一路并不是平台的到道路,总要有点意外和惊喜。人嘛!…

152.网络安全渗透测试—[Cobalt Strike系列]—[会话管理/派生]

我认为,无论是学习安全还是从事安全的人多多少少都会有些许的情怀和使命感!!! 文章目录 一、会话管理1、实验环境2、会话派生(1)128的cs会话派生给128的cs本身(2)128的cs会话派生给…

森林攻略

1.存档攻略 C盘/ Users / Administrator / AppData / LocalLow / SKS / The forest / 一列数字 你保存的存档,就在那个名称全是数字的文件夹中,只需把其中的存档文件保存在U盘或网盘中,下次玩时,把保存的存档文件放到存档文件夹…