iOS内购丢单的解决方案

    iOS内购这块的开发一直比较麻烦,除了各种购买选项的问题,最恶心的问题就是丢单问题。
    丢单就是iOS内购过程中付了钱,但是App没有发货的问题。要解决丢单问题,先要梳理一下整个购买的过程:

  1. 调用服务器接口创建订单
  2. 调用内购的api完成购买
  3. 获取receipt、transactionIdentifier发送给服务器
  4. 本地服务器拿到receipt向苹果发起验证,并回调结果给App

以上就是整个购买的过程,现在我们根据每一步分析下可能出问题的点


1. 调用服务器接口创建订单

这一步的操作就是让服务器创建当前购买商品的订单,返回结果失败或者成功,这里基本不会出问题,成功就继续接下来的流程,失败的话,客户端返回失败的提醒就行。


2. 调用内购的api完成购买

绝大多数的问题都出在这里,在这里说一下我遇见的坑

  1. 客户在付完款之后,直接杀死了app。
  2. 在支付过程中,若当前账户里的钱不够,且没有绑定银行卡、微信或者支付宝,会触发一个绑定机制,但是用户在点击去绑定时候,- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions,会返回一个失败的transaction,当用户完成支付,又会返回一个成功的transaction。由于我们之前使用RMStore这个第三方插件,他在处理回调的时候有这样一个机制,每次发起购买RMStore都会把回调的block存储到RMAddPaymentParameters这个对象里面,当第一次错误回调返回时,会把RMAddPaymentParameters里面的block取出来并执行,执行之后,持有这个对象的数组会把这个对象移除,所以当第二次成功的回调返回时,再想去执行block,但是持有这个block的对象已经被移除了,导致了非常多的丢单。

对于第一个问题,内购的api有一个监听机制,在每次app刚启动的时候调用[[SKPaymentQueue defaultQueue] addTransactionObserver:self];方法,- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions,会回调所有未执行[[SKPaymentQueue defaultQueue] finishTransaction:tran];的transaction,这个时候再去和服务器进行订单的验证。这里还有一个很麻烦的问题,在上个流程中,调用服务器创建了订单,会返回一个订单号,验证的时候一般都是把订单号,以及receipt,transactionid一起发送给服务器,但是这里是拿不到订单号的。针对这个问题,网上有人用applicationUsername这个字段去存入订单号,但是也有一些人在使用这个字段的时候出现了Bug(App杀死后,获取这个字段的值为空,参见下面的引用),为了保险,这里还是不用字段。我的解决方案是在用户创建完订单之后,存储当前的订单信息,用户token等等,当购买完之后,再去取这个订单信息,完成验证,删除订单,这个方案的核心是永远只存储一个订单,若在购买的时候有未完成的订单,必须先验证之前的订单,验证完之后,再去发起新的购买,这样就能规避多个transaction不能匹配订单号的问题;
    对于第二个问题,这个问题好解决,不用这个第三方就行,自己造个轮子,基本的购买逻辑很简单,没必要用这个插件。当- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions返回的transaction的state为failure时候,finish这个transaction,state为purchsed的时候,去验证。
    这里还有一个问题,finishTransaction:的调用时机,一定要在与服务器完成验证之后,再去调用这个方法,因为在与服务器的验证的过程中,也是会出现错误的,如果再购买成功回调之后就调用这个方法,验证错误的订单也被finish了,下次去取transaction的时候,就取不到了,这样就造成了丢单问题。


3. 获取receipt、transactionIdentifier发送给服务器

    这里的逻辑基本就是自己的了,跟苹果内购关系不大,把订单、receipt等信息发给服务器就行,唯一需要注意的问题就是网络错误,这个时候我会做一个轮循,在发生错误的时候,轮循几次,超过这个次数,认为验证失败,等到用户购买下一个商品、或者app重新启动,会重新验证这个订单(当然,这个情况是极少的!为了严谨,做了以上处理)


4. 本地服务器拿到receipt向苹果发起验证,并回调结果给App

    终于到最后一步了,这里有一个地方需要注意一下,就是本地服务器与苹果服务器验证的方式,之前我们公司出了个问题,在调用/verifyReceip这个接口去验证,苹果会返回一个数据status,它们认为status等于0就是完成购买了,但是这个字段的含义并非如此

For iOS 7 style app receipts, the status code is reflects the status of the app receipt as a whole. For example, if you send a valid app receipt that contains an expired subscription, the response is 0 because the receipt as a whole is valid.

    它只是反映这个receipt是不是完整的,并不能证明这次购买完成。正确的做法应该是服务器拿到此次的transaction和receipt之后,解析receipt,拿当前的transaction和receipt里的transaction数组去比对,若数组中有这个transaction对应的transactionid,则认为购买成功。
    苹果服务器返回的错误码中,我们只需留意21005即可,它代表验证服务器当前不可用(当然这种情况是级级级小的!为了严谨),处理的方式和网络错误的处理方式是一样的。


内购流程图.png

Receipt Validation Programming Guide

applicationUsername的坑

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 关于苹果内购(IAP)的一些问题以及那些坑: 最近在研究苹果内购功能,所以,在网上找了一些资料,进行学习。但是,内...
    魔芋Brace阅读 7,331评论 0 5
  • 自己开发的视频直播项目,牵涉到充值金币,用到了苹果公司的内购,趴坑了两天,这里总结下实现苹果内购。 一. 创建测试...
    Leo丶Dicaprio阅读 3,358评论 8 7
  • iOS应用如果涉及到支付功能,分为两类:第三方支付和苹果内购。那么什么情况下选择使用第三方支付,又在什么情况下选择...
    ZfRee阅读 38,773评论 36 66
  • 参考借鉴了一下几篇文章(在这里很感谢各位作者大大做出的总结和方案): http://blog.csdn.net/a...
    辉546阅读 13,855评论 3 12
  • 城老已经几度秋,昔时常事又曾留? 方山依故结清友,深巷无人藏忘忧。 清友:茶 忘忧:酒 唐代姚合品茶诗云:“竹里延...
    无是也阅读 462评论 2 0