美文网首页ios基础支付ios开发学习系列
【iOS开发】IAP开发的那些坑

【iOS开发】IAP开发的那些坑

作者: 出头天等待咸鱼 | 来源:发表于2016-07-05 14:07 被阅读10163次

    最近正在做的项目,涉及到了IAP(In-App Purchase),即苹果的应用内购买。在开发过程中遇到了各种各样的状况,IAP的开发步骤在网上有很多十分详尽的教程,不需赘述,本文重点介绍说明在IAP开发过程中遇到的坑,并探讨相对合理的解决办法。

    一、IAP类型与用户系统



    绝�大部分iOS应用,都会维护一套自己的用户系统,然而IAP是使用苹果的用户系统(Apple ID)来进行购买的,因此就会产生一个问题:

    通过苹果的用户系统(Apple ID)的购买结果或行为,如何与应用本身的用户系统进行关联?

    很简单的�情况就是,应用内的不同用户使用同一个Apple ID进行IAP,或者是应用内同一个用户使用不同Apple ID进行IAP,要如何处理。

    解决这个问题之前,首先要明确IAP的类型,以及每种类型的特性。下面是在iTunes Connect创建IAP时的提示:

    可以看到IAP总共有5种类型,虽然苹果对每种类型的说明很详细,并且都加上了举例说明,但仍然没有明确的信息解决之前的问题。在查阅了苹果IAP的开发文档后,我发现了下面的表格:

    这个表格中表明了不同类型IAP的在使用同一Apple ID购买时的次数限制,经过测试总结如下:

    • 非消耗型

    同一Apple ID只能购买一次,再次购买会提示已购买。

    无法与应用的用户系统关联,因为同一Apple ID无法为多个应用用户购买。

    • 消耗型

    同一Apple ID可以购买多次,�每次购买流程几乎完全相同。

    可以与应用的用户系统关联,因为每次购买与Apple ID几乎无关系。

    • 自动续订订阅

    同一Apple ID可以购买多次,但在购买时会检查是否购买过,如果购买过并且权限未过期,系统会提示已购买而无法再购买。

    无法与应用的用户系统关联,因为同一Apple ID购买时会检查购买纪录并校验权限,未过期用户无法重新购买。

    • 非续订订阅

    同一Apple ID可以购买多次,但在购买时会检查是否购买过,如果购买过并且权限未过期,系统会提示续期而可以再次购买。

    可以与应用的用户系统关联,但同一Apple ID在购买时会检查购买纪录�并校验权限,未过期用户会有续订提示,这种系统提示在一些场景下是不合适的。

    • 免费订阅

    同一Apple ID只能购买一次,再次购买会提示已购买。

    无法与应用的用户系统关联,因为同一Apple ID无法为多个应用用户购买。

    p.s. 有一种比较暴力的做法,就是将应用的用户系统与Apple ID的用户系统进行关联,一个应用用户对应一个Apple ID。这种方法实质上是将两个用户系统进行统一,但这种方法会产生很多副作用,建议尽量不要使用。

    �二、IAP流程与receipt校验



    在选取了合适的类型之后,就是实现IAP的基本流程,客户端和应用后台的主要任务是处理购买成功后,如何校验用户购买结果:

    按上图的流程,主要是处理逻辑是在最后一步Delivering Products的Observer is Called,即购买之后系统回调之后的处理。这里最核心的部分就是购买结果的校验,即receipt校验。

    在用户IAP成功后,客户端或服务器可以使用receipt向appstore请求,获取用户的购买记录,得到一份json格式的数据,通过数据解析来�校验用户购买的产品类型、权限、期限等信息。

    • IAP是否可用判断

    这里主要注意的是对越狱用户要添加额外的判断,因为越狱用户是无法进行IAP的,因此在入口就要进行判断,其次调用canMakePayments函数,判断IAP是否可用,再次校验product是否合法。

    当然也可以加上应用的一些判断,如登录状态,是否已经购买等。

    • finishTransaction的调用时机

    所有的教程都会说在购买完成回调时,要调用finishTransaction函数,但这个函数具体会产生哪些作用并没有具体说明。

    (1) 问:如果不调用finishTransaction会有什么影响?
    :appstore会认为购买流程未完成,如果应用启动时就注册了IAP的observer,那么会出现应用每次启动时,都会调到回调,传说中的Apple ID密码的频繁弹框大部分是这个原因造成的。

    (2) 问:调用finishTransaction函数之后,对receipt有什么影响?
    :在上一节中的表格中,对于不同类型IAP的receipt的保存有差别的是消耗型,它只保存一次。保存一次的意思就是说,在购买成功后会有消耗型的receipt信息,但在调用finishTransaction函数之后,消耗型的购买信息就会被删除。因此对于消耗型IAP,建议在校验完成后再调用finishTransaction。

    • transaction_id和original_transaction_id

    在每一条购买信息数据中,有两个容易混淆的字段:transaction_id和original_transaction_id。

    (1) transaction_id
    每一次购买记录生成唯一标识,与SKPaymentTransaction类中的transactionIdentifier相对应

    (2) original_transaction_id
    在restore时使用,与SKPaymentTransaction类中的originalTransaction�相对应
    自动续订订阅类型,所有的购买记录都相同

    • in_app与latest_receipt_info

    测试时发现,这两个字段的数值几乎相同,不过有几点需要注意:

    (1)自动续订订阅类型,在到期后会再生成一条购买记录,这条记录会出现在last_receipt_info里,但不会出现在in_app里

    (2)自动续订订阅类型可以配置试用,试用记录只有在latest_receipt_info里,is_trial_period字段才是true

    (3)消耗型购买记录有可能不会出现在latest_receipt_info,因此需要检查in_app来确保校验正确

    • restore的处理

    如果应用中使用了非消耗型、自动续订订阅型、免费订阅型的IAP,需要提供restore的入口,并调用restoreCompletedTransactions函数进行恢复购买。

    在恢复购买的时候,要注意�要使用originalTransaction的信息来做校验,特别是购买时的id,因为在restore的时候生成的transaction的id,与初始购买不相同

    ��三、IAP测试



    IAP测试只要添加沙箱测试账号就可以进行测试了,不过在测试订阅类型时,要注意测试的时间长度与实际的时间长度的对应关系:

    ��四、IAP审核



    在提交审核时,一定要注意在应用描述中添加IAP的具体说明,包括种类、价格、服务等,同时在应用描述及应用中添加服务条款。

    [1]In-App Purchase Programming Guide
    [2]Receipt Validation Programming Guide

    相关文章

      网友评论

      • Cherry_06:你好,请问自动续订商品到期用户续订后客户端还会收到凭证么?貌似有些收不到。。。
      • _喵了个喵_:想咨询下,如果为非消耗型购买,怎么跟用户做关联,同一Apple ID只能购买一次,再次购买会提示已购买,其他用户可以用同样的一个Apple ID就可以免费获取服务
        毛癫子:分享iOS开发的知识,解决大家遇到的问题,欢迎大家投稿~这是小编的一个IOS开发交流群:714042473。
      • 超_iOS:再次阅读大神的文章,有个疑问:
        只有消耗性才会从凭证里移除么?其他类型都是会永远存在在购物凭证里么?
      • 青木KON:非续期订阅 怎么设置过期时间?
        这个优秀瓜:还有一点要补充一下,如果你的App本来有用户体系,也就是你的后台本来会向你提供用户信息,就不必设置恢复购买的按钮了。因为会员一登录就能获取到会员状态了
        这个优秀瓜:这个苹果后台不提供设置,由你的服务器来设置。
        你可能会疑惑,如果苹果后台不提供设置,
        1、它怎么判断过期?
        2、恢复内购(restore)该如何实现?

        关于第一点,其实苹果并不判断过期,在购买过一次非续订订阅的产品以后,接下来再次购买的行为都会弹出两次确认页面,第二次页面有提示内容说:【你已经购买过此产品,是否再次购买(大致这样)】。从而知道,苹果后台并不知道有没有到期。

        第二点:苹果官方文档说,要非续订订阅也要实现恢复内购【restore】。从上一点我们知道,苹果不知道过期时间,那又何来的实现恢复内购呢?
        其实,苹果这里所要求的实现恢复内购功能是要求我们的服务器提供【恢复内购】的功能。也就是:我们的客户端有个【恢复内购】的按钮,点击这个按钮,调用我们服务端的恢复内购API,服务端收到客户端的消息,然后去数据库查询这个客户端(用户)当前是否还在【我们规定】的订阅周期里面,如果是,就恢复客户端(用户)的会员身份。
      • Hengry:in_app 中出现多个订单信息,应该拿哪条处理呢
        敏敏哇敏敏:同问 ,请问解决了吗?
      • ilnaw:你好想问下 我的app is需要购买一次性服务 属于非消耗型,你上述中非消耗型无法与本身系统用户关联,怎么解决这种问题
      • 黄易女民工jiang:我做沙盒测试的时候 app的bundleId 没有在appStore上架过 appStoreReceiptURL拿出来的东西服务器不能校验成功 transactionReceipt这个却可以 你有过这方面的了解么?是不是因为appStore并不能查到我们的app信息 但是服务器那边用的校验已经是用的苹果提供的沙盒校验
      • 洁简:商品一直返回0,怎么办呢?
      • 超_iOS:消耗型校验完成后再调用finishTransaction,那么如果校验失败了岂不是要一直校验了,还有启动监听到底写到哪里比较好?
        出头天等待咸鱼:@李二超
        启动监听我是写在了didFinishLaunchingWithOptions里;
        消耗型调用finishTransaction之后,程序上就无法再找到这条购买记录了,所以如果校验失败了,尽量不要调用,至于校验失败后的重试逻辑可由自己来控制;
        有一点需要注意,启动监听后,未调用finishTransaction的购买会自动调用到回调函数- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
      • 陆大胖:越狱版可以做内购,苹果没有对比做任何
        限制,跟没越狱是一样的
        陆大胖:@牛佑面面 你说得对,任何购买都要做票据的校验。我不清楚我们说的越狱版意思是否一样,我说越狱版是只越狱设备使用appstore下载的应用。我说的无区别是指苹果不会对这种情况作区分。如果这种情况下你的某些票据会出错,建议你做下统计,我们也在做。但是可以明确的告诉你,上面的情况下,票据检验是可以成过
        出头天等待咸鱼:@陆大胖 越狱版是可以做内购,但越狱版购买成功后的receipt是无法向appstore做校验的,至少我在做自动续订购买时收到越狱用户发到后台的receipt数据是不正确的。如果将这种购买不通过appstore校验而判断为有效,有可能会有用户伪装越狱来恶意购买。

      本文标题:【iOS开发】IAP开发的那些坑

      本文链接:https://www.haomeiwen.com/subject/jhvmdttx.html