⼀一、普通⾃自动续费⽀支付流程
1.FE⻚页⾯面从server获取会员商品列列表做显示,server从xpage中读取配置,并结 合当前⽤用户是否已开通过⾃自动续费来决定是否返回⾃自动续费商品(如果已开通过 ⾃自动续费,不不展示)。
2.从FE⻚页⾯面购买⾃自动续费商品,端上收到商品id序号,这个商品id是不不包含前缀 的,端上需要拼上前缀。然后端上使⽤用完整的商品id调⽤用IAP Kit来去appstore获 取⽀支付商品信息SKProduct,此时会弹出⽤用户付款弹窗。⽤用户输⼊入apple账号, 发起付款成功。
3.端上会收到⾸首次购买凭证(凭证的存储/重试等逻辑同普通的会员购买),和 original_transactionid(后⾯面有具体叙述),并上传给 server(naapi/iap/orderpayydvip),server⾸首先把凭证和transactionid做存 储。然后把original_transactionid和⽤用户做绑定,创建订单返回给端,并异步的 去appstore校验证书。
4.server凭证解析之后判断凭证合法与否,并按照证书类型,给⽤用户增加相应的 VIP时⻓长。同时根据返回的续订状态,更更新⽤用户的订阅状态。
5.端上轮询的去查询订单状态是否成功(naapi/pay/ydpaycheck),返回状态码 1是成功,997⽆无效凭证,996没有订单,995⾃自动续费已过期,998重复凭证 (对于重复凭证,端上会提示⽤用户已订阅)。
6.server每天定时跑脚本,遍历所有的存储证书,去appstore做校验,然后更更新 ⽤用户的订阅状态和时⻓长。
7.⽤用户⾃自动续费的时候端上⽆无感知,在端下次重启的时候,会收到⾃自动续费的凭 证,此时端还会上传original_transactionid和凭证给server,server通过 original_transactionid寻找对应的⽤用户,同步骤3和4,判断⽤用户当前的订阅状 态,去appstore检验证书,并给⽤用户续上会员时⻓长。
⼆二、详细 测试环境
1.release appstore的包,⽤用正式账号,只能在越狱⼿手机上测,但新建的商品没 有审核过前,正式账号在appstore的包会返回⽆无效商品。 2.release adhoc的包,只能⽤用沙盒账号,在注册了了的那⼏几个⼿手机上测试。 3.debug的包,只能⽤用沙盒账号。
4.testflight的包,也是沙盒账号。 沙盒环境时间是加速的,1周相当于3分钟,1个⽉月是5分钟,⼀一次购买会⾃自动续费 6次。 ⾃自动续费要取消,⽤用沙盒账号是⽆无法操作的,因为沙盒账号没法登陆appstore, 不不登录appstore没法管理理取消⾃自动续费。 要测试⾃自动续费的取消,在沙盒环境,第6次沙盒环境会⾃自动取消⾃自动续费。
⾃自动续订订阅与⽤用户账户体系
1.Apple ID⽆无法与应⽤用的⽤用户系统关联
同⼀一Apple ID可以购买多次,但在购买时会检查是否购买过,如果购买过并且权 限未过期,系统会提示已购买⽽而⽆无法再购买。 Apple ID⽆无法与应⽤用的⽤用户系统关联,因为同⼀一Apple ID购买时会检查购买纪录 并校验权限,未过期⽤用户⽆无法重新购买。 ⽐比如:apple账号apple1购买了了⾃自动续费的vip,这时候我们充值了了会员给我们的 ⽤用户user1,如果⽤用户切换了了user2登录。 还⽤用apple账号apple1来给user2充值,是充不不了了的。
⽤用户A,同⼀一个apple账号,买完⾃自动续费,然后⽴立即取消。再切换⽤用户B,这时 候B⽴立即去买,是不不花钱的。 会提示他这次续订之后,1个⽉月之后⽣生效。爱奇艺是提示这次购买没成功,并且 提示同⼀一个appleid只能给⼀一个账号充值。 ⼀一个⽉月之后,A账号到期了了,这时候可以给B买了了,这时候会花钱,给B充值。
2.购买凭证与⽤用户做绑定
考虑以下场景: 登录⽤用户A,⽤用apple账号1开通⾃自动续费,然后切换账号B,等5分钟(沙盒相当 于1个⽉月),重启应⽤用(⾃自动续费的证书会在应⽤用启动的时候下发),如果此时 server不不做凭证和⽤用户的绑定,端上当前登录的⽤用户B,上传凭证,会把⽤用户A⾃自 动续费的证书充值给⽤用户B。
要解决会员购买和⽤用户账号关联:
1.)original_transactionid,⾃自动续费订阅的⾸首次⽀支付会⽣生成⼀一个 original_transactionid,之后的每次续费证书⾥里里,都会包含这个 original_transactionid。我们可以使⽤用这个id来和⽤用户的账号关联,来保证即使 切换⽤用户,⾃自动续费还是会充到原来的账号去。 2.)端上上传⽀支付证书,并且上传original_transactionid。 3.)server端把每次购买的⽤用户上传的证书记录下来,并⽤用orgin_transctionid和 ⽤用户进⾏行行绑定,如果⽤用户B上传证书的时候,server发现original_transactionid和 A做的关联,并且A的会员续费状态还在继续,就提示B不不能充值,并继续给A 充。如果A已不不在⾃自动续费状态,就给B充值,把A解绑,orgin_transctionid和B 绑定。
3.半账号/未登录⽤用户不不⽀支持购买,也不不⽀支持⾃自动续费 ⽤用户没登录的时候,在FE⻚页⾯面会做登录跳转。但存在登录的时候⾃自动续费,然后 退出登录,中间⽤用户⾃自动续费了了,下次启动应⽤用,会收到续费凭证,此时发现是 未登录,或者半账号,就直接忽略略到此凭证,(但不不设置finishtransaction,让 系统记住这个凭证),等⽤用户登录的时候再上传。
端上推介促销商品的⽀支付流程
a.)7天免费+⾃自动续费 ⾸首次订阅不不需要花钱,端上会收到凭证,并上传这个凭证给server(naapi/iap/orderpayydvip),server创建订单返回给端,并异步的去 appstore校验证书。 端上轮询的去查询订单状态是否成功(naapi/pay/ydpaycheck),返回状态码1 是成功,997⽆无效凭证,996没有订单,995⾃自动续费已过期,998重复凭证 (对于重复凭证,端上会提示⽤用户已订阅)。 server凭证解析之后会发现is_trial_period的试⽤用期字段,会给⽤用户的会员加7 天。 b.)⼀一个⽉月半价+⾃自动续费 同上,只是凭证解析的时候⾸首次返回is_in_intro_offer_period,标识是在打折阶 段,除了了对账,⽆无需特殊处理理。
注特殊情况: 端上在购买的时候会收到凭证,如果端不不退出,这个时候⾃自动续费了了,端上是⽆无 感知的,收不不到⾃自动续费的凭证。
只有在下次启动的时候,才会收到凭证,如果⾃自动续费了了多次,会⼀一次返回多个 凭证。 如果当前已订阅,⽤用户⼜又买了了⼀一次,这时候会提示已订阅,不不会扣款,同时IAP 会返回最近的⼀一次付款的收据。
⽐比如transIDN1000000411551481, date:2018-06-27 07N56N30 但是下次启动的时候,他会把所有⾃自动续费的历史收据全返回来: state:1, transIDN1000000411553700, date:2018-06-26 03N38N38
state:1, transIDN1000000411553701, date:2018-06-26 01N51N42
state:1, transIDN1000000411553702, date:2018-06-26 05N32N39
state:1, transIDN1000000411553703, date:2018-06-26 01N46N42
....... 另外,⽆无论我们⽤用什什么时候的历史证书去appstore校验,他都会给我们返回最新 的证书,或者最新过期的证书(后⾯面证书解析会说明)。 基于以上情况,我们对⾃自动续费的VIP商品返回的多个证书,只取时间戳最⼤大的 ⼀一个去server校验。
订阅群组
⾃自动续费订阅必须在⼀一个订阅群组中。 ⽤用户同时只能在⼀一个订阅群组⾥里里订阅⼀一个。
⽤用户可以再app appstore的设置中管理理他的订阅组,他能看到这个订阅组⾥里里的多 个订阅,以及他当前的订阅是哪个,还可以取消。
[图片上传失败...(image-1c690-1571314172360)]
⽐比如这⾥里里是⼀一个旅⾏行行商品的订阅群组,包含⼏几个订阅: 太平洋+印度洋1个⽉月的⾃自动续费是28.99, 太平洋的⼀一个⽉月的⾃自动续费是$1.99... ⽤用户只能在这个订阅群组⾥里里买⼀一个,如果想买其他的,可以切换过去。
⾃自动续期订阅扣税
⼀一个订阅者累计续订了了⼀一年年,第⼀一年年70%,第⼆二年年85%。 如果订阅者⾃自动续期订阅的连续付费服务不不⾜足⼀一年年(包括推介促销价阶段,免费 试⽤用阶段除外),我们将收到订阅价格的 70%,扣除相应税款。 ⽤用户在订阅群组中切换,他的累计⽇日期还会继续增加。⽤用户在60天以内取消订 阅,重新订阅,也会继续增加这个累计。
推介促销价
普通订阅提示如下:
[图片上传失败...(image-89f438-1571314172360)]
推介促销价的订阅:
注意: 1.设置完推介促销价,会有⼀一段时间的⽣生效时间,2-3个⼩小时不不等(设置完在端 ⾥里里购买,发现没出现下⾯面的1周免费/前⼀一个⽉月xx每⽉月的弹窗,等等再试就好 了了)。 2.推介促销价 在最开始订阅的⼀一段时间可以提供打折价,或者免费试⽤用。可以提供以下推荐价 格类型之⼀一: 1.)随⽤用随付 ⽐比如前三个⽉月1.99美元每⽉月(前⼏几个⽉月每个⽉月都要付个优惠价),后⾯面恢复标准 价9.99美元每⽉月。
可设定以下时限:
1 周订阅,1 ⾄至 12 周 1 个⽉月订阅,1 ⾄至 12 个⽉月 2 个⽉月订阅,2、4、6、8、10 和 12 个⽉月 3 个⽉月订阅,3、6、9 和 12 个⽉月 6 个⽉月订阅,6 和 12 个⽉月 1 年年订阅,1 年年
2.)提前⽀支付 ⽐比如先9.99元体验6个⽉月(⼀一次性买N个⽉月),体验完之后恢复39.99元每年年的续 订。
可设定以下时限:1 个⽉月、2 个⽉月、3 个⽉月、6 个⽉月、1 年年 3.)免费试⽤用 先使⽤用⼀一段时间,完了了⾃自动续订。
时限可以是 3 天、1 周、2 周、1 个⽉月、2 个⽉月、3 个⽉月、6 个⽉月或 1 年年。⼀一个⽉月 的免费试⽤用在 28 到 31 天内不不等。
[图片上传失败...(image-d04d56-1571314172360)]
[图片上传失败...(image-284353-1571314172360)]
[图片上传失败...(image-f8b75f-1571314172360)]
[图片上传失败...(image-2e519f-1571314172360)]
[图片上传失败...(image-4691ea-1571314172360)]
[图片上传失败...(image-653e9c-1571314172360)]
[图片上传失败...(image-88f58f-1571314172360)]
[图片上传失败...(image-3948ac-1571314172360)]
综上,我们的会员⾃自动续费都在⼀一个订阅群组⾥里里,包含如下⼏几种类型 (productid都是不不同的): a.)⼀一个⽉月的会员
1.)⾃自动续费1个⽉月12元 2.)7天活动价0元 + ⾃自动续费1个⽉月12元 3.)第⼀一个⽉月6元 + 之后⾃自动续费1个⽉月12元
b.)未来可能有1年年/3个⽉月/半年年的⾃自动续费等等
注: a和b之间可以切换但不不能同时购买。 a的123推介促销价⼀一个apple账号⼀一⽣生只能使⽤用⼀一次。 a的123推介促销价之间,可以重复买享受活动价,⽐比如⽤用户买了了1,之后可以买 2,享受⼀一次7天免费,之后再买2,就没有活动了了,就是单纯的续费12元⼀一个 ⽉月。
基于以上原因: 产品策略略,开通连续包⽉月后在会员⻚页档位上不不再显示连续包⽉月档位,防⽌止⽤用户
理理解误区。
涨价
⽼老老⽤用户享受当前已订阅价格,如果你给某个订阅涨价了了,苹果会通过邮件和push 来通知受影响的⽤用户, 并询问他们是否接受新的价格。如果他们不不接受或者没响应,订阅会在结束后⾃自 动取消。
⾃自动扣费
苹果在订阅到期的前10天会检查,是否有不不能续订的问题阻⽌止⾃自动续订。 ⽐比如⽤用户的⽀支付条件不不能正常⽀支付了了,商品加价了了,商品下架了了。 苹果发现问题会通知⽤用户。
在过期的24⼩小时前,苹果会⾃自动续费。
如果是账单相关的问题,苹果会在60天内重复尝试续订,可以在receipt的 is_in_billing_retry_period 标签中查看appstore是否还在尝试续订。
退款
⽤用户联联系苹果客服退款,只有在⽤用户偶然买了了错误的商品的时候才会申述成 功。
客服会帮助取消续订,并退回⽤用户全部或部分款项。 要想检查是否⼀一个⾃自动续订被客服给强⾏行行取消并退款了了,会收到取消续订的收 据,去看receipt的Cancellation Data字段,如果这个字段包含了了⼀一个⽇日期,可以 忽略略expiration data,这个续订是被取消了了。这种情况可以当做⽤用户没买过来处 理理。
另外如果注册了了
statusUpdateNotification(appstore发给server) 要获取最新的订阅状态的notification,在appstore connect⾥里里配置订阅状态的接 收URL。 Appstore和你的server建⽴立连接需要ATS协议,App Transport Security (ATS) “Requirements for Connecting Using ATS”。 ⼀一个符合 ATS 要求的 HTTPS,应该满⾜足如下条件: Transport Layer Security协议版本要求TLS1.2以上 服务的Ciphers配置要求⽀支持Forward Secrecy等
证书签名算法符合ATS要求等 。 基本上https都符合ATS的要求,这个可以去https://myssl.com/ats.html? domain=appwk.baidu.com&port=443⽹网站做下校验。 nsurl --ats-diagnostics --verbose https://appwk.baidu.com/naapi/iap/ydvipautopaylistenerhttps://apptransport.info/appwk.baidu.com/naapi/iap/ydvipautopaylistener 成功收到通知后,你的server返回http 200即可,不不需要返回数据。 如果返回了了50x或者40x,appstore会重试发消息。隔⼀一段时间重试⼏几次,到⼀一 定失败次数不不发了了。
在⽤用户订阅状态发⽣生变更更的时候,appstore会通过post请求,给server传⼀一个 json。key如下:
[图片上传失败...(image-dbcaa-1571314172360)]
[图片上传失败...(image-376f12-1571314172360)]
[图片上传失败...(image-49ba3f-1571314172360)]
[图片上传失败...(image-edfa81-1571314172360)]
[图片上传失败...(image-ae55a4-1571314172360)]
⾥里里⾯面的字段和端上的证书基本⼀一致。 app store会在如下条件时候给server发通知:
这⾥里里问题⽐比较多,我们在最初测试的时候,发现Cancel,renewal都没有回调, 后来发现对于这⼏几种情况的理理解,官⽅方的论坛上有补充。
Let me clarify the other notifications types
CANCEL - Subscription was canceled by Apple customer support. Check Cancellation Date to know the date and time when the subscription was canceled.
Clarification - the term cancel is the specific case where the user contact Apple Care, requests a refund for the auto-renewing subscription In-App Purchase, is granted the refund, and the auto-renewing subscription has the cancellation_date set. This event is not the same as when the user enters their iTunes account - Subscription section, and indicates that they choose not to allow an existing auto- renewing subscription to renew. There is no notification type for this event. I call this the
[图片上传失败...(image-73df8a-1571314172360)]
“EXPIRE” event - there is no server-to-server notification when the user makes this choice.
The only way for an application to detect that the auto-renewing subscription has simply expired is for the app process to validate the appStoreReceipt and to find that there is no longer an iAP item showing the expires_date greater than todays date. The process should also check for the presence of the is_in_billing_retry_period field in the most recent entry to determine whether the App Store is attempting to renew the auto-renewing subscription.
RENEWAL - Automatic renewal was successful for an expired subscription. Check Subscription Expiration Date to determine the next renewal date and time. Clarification - in general, iTunes will attempt to charge the user account a day before an auto-renewing subscription is scheduled to expire. If the renewal is successful, there is no server-to server notification because the auto-renewing subscription did not enter into an expired state. However, in the few cases that iTunes is unable to renew the subscription (generally there was a connection problem with the credit card server) and the auto-renewing subscription is not renewed before the expiration_date passes, the auto-renewing subscription is technically considered “expired”. However, iTunes will still continue to attempt to renew the subscription. It iTunes is successful, then the “RENEWAL” event is sent. for this reason, the advice is presented - “Check Subscription Expiration Date to determine the next renewal date and time.”
For a normal renewal which is successful before the subscription actually expires, validate the appStoreReceipt and check the contents of the latest_receipt_info to verify that there is an auto-renewing subscription in-app purchase item where the expires-date is later than the current date.
INTERACTIVE_RENEWAL - Customer renewed a subscription interactively after it lapsed, either by using your app’s interface or on the App Store in account settings. Service is made available immediately.
Clarification - If a customer purchases an auto-renewing subscription then after some period of time, allows the subscription to expire, that is their choice.
However later on, iTunes provides the user the option to restart the auto- renewing subscription in their account -> Subscription page. Alternatively, the user could purchase the AUTO-RENEWING SUBSCRIPTION in the app. When either event occurs, iTunes sends this notification.
DID_CHANGE_RENEWAL_PREFERENCE - Customer changed the plan that takes affect at the next subscription renewal. Current active plan is not affected. Clarification - If your app offers multiple items in an auto-renewing subscription group, then if the user has purchased a higher level item and attempts to switch to a lower grade auto-renewing subscription item (this is considered an auto- renewing subscription downgrade), then this notification is sent to your process. The higher level auto-renewing subscription will continue until the expiration_date - at which time the downgrade auto-renewing subscription will be put into effect.
As to the second part of your question, the iTunes Server group manages the appStoreReceipt contents. They have not documented how the field original_transaction_id is managed in the case that the customer cancels an auto-renewing subscription, then later decides to purchase (re-new or re- activate) the subscription. The cancellation_date field will only be present in the auto-renewing subscription record which was refunded. If later the user decides to purchase the auto-renewing subscription, there will be a different record with more recent information. I woud not make any assumption as to the value of the original_transaction_id field between the two records.
综上: INITAL_BUY ⾸首次买 Cancle 客服给取消的 RENEWAL 过期了了,但是苹果⾃自动重试过了了⼀一段时间⼜又续费上了了 INTERACTIVE_RENEWAL ⽤用户取消了了,⼜又重新订阅 ⽤用户取消的事件,收不不到通知。 ⾃自动续费的事件,也收不不到通知。
注意:
1.这⾥里里的回调是与⽤用户⽆无关的,那去区分是哪个⽤用户的订阅状态变动。需要我们 每次端上上传证书的时候,server记录下originnal_transctionid和userid的绑 定。 2.⽤用户取消,和⾃自动续费如果端上不不传证书,server是不不知道的,如果想对账, 或者给⽤用户发push。 那server只能跑定时脚本,每天或者在过期的第⼆二天,⽤用证书再请求下App Store校验下,他会返回最新的证书或者过期证书,看看新的过期时间是否变了了 就可以判断了了,于是在端上每次上传证书的时候,server也要记录下端上的证 书。
⽀支付证书
⾃自动订阅的证书⾥里里包含⼀一个⽤用户订阅状态的实时信息。 以便便你决定⼀一个订阅当前是否是有效的,判断⼀一个订阅已经使⽤用了了多少天,判断 ⽤用户是否是新订阅的⽤用户,续订订阅,和已经过期的订阅者。
注意: ⾃自动续费的证书校验需要上传的参数形式多了了⼀一个password字段传秘钥。 ⽐比如:
curl -d ‘{ “password”:”yyyy” “receipt-data”: “xxxx”}’ https:/sandbox.itunes.apple.com/verifyReceipt 还有个字段⽤用来控制ios7之后新证书是否返回精简内容的。 否则会返回:
21004 The shared secret you provided does not match the shared secret on file for your account. Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.
两种证书 1.iOS7以前的证书(新证书的获取在某些极端情况下会获取不不到,也需要⽼老老证书 ⽼老老兜底;另外server也没有做新证书的适配,⽬目前就使⽤用⽼老老证书): 过期的证书: {
auto_renew_product_id = "com.baidu.yuedu10000001", auto_renew_status = 0, // 已过期 expiration_intent = "1", // 只有在RENEWAL和INTERACTIVE_RENEWAL情
况返回
is_in_billing_retry_period = "0" //是否发起⽀支付重试 latest_expired_receipt_info = { //过期才有最后过期证书信息
bid = "com.baidu.yuedu", bvrs = "5.9.0", expires_date = "1532952269000"
expires_date_formatted = "2018-07-30 12N04N29 Etc/GMT", expires_date_formatted_pst = "2018-07-30 05N04N29
America/Los_Angeles", is_in_intro_offer_period = "false", //是否在打折促销阶段 is_trial_period = "false", //是否在免费试⽤用阶段 item_id = "1418505157", original_purchase_date = "2018-07-30 10N16N48 Etc/GMT", original_purchase_date_ms = "1532945808000",original_purchase_date_pst = "2018-07-30 03N16N48
America/Los_Angeles", original_transaction_id = "1000000424240109", product_id = "com.baidu.yuedu10000001", purchase_date = "2018-07-30 11N59N29 Etc/GMT", purchase_date_ms = "1532951969000", purchase_date_pst = "2018-07-30 04N59N29 America/Los_Angeles", quantity = "1", transaction_id = "1000000424307924", unique_identifier =
"ad9e3730489447ade8bd574c806a80b7161eecbd", unique_vendor_identifier = "EF5BB5D5-2800-40FD-9B6F-
E3C41C19AD0D", web_order_line_item_id = "1000000039700780",
}, receipt = { //我们传的要校验的证书的解析
bid = "com.baidu.yuedu", bvrs = "5.9.0", expires_date = "1532952269000", expires_date_formatted = "2018-07-30 12N04N29 Etc/GMT",
expires_date_formatted_pst = "2018-07-30 05N04N29 America/Los_Angeles",
is_in_intro_offer_period = "false", is_trial_period = "false"
item_id = "1418505157", original_purchase_date = "2018-07-30 10N16N48 Etc/GMT", original_purchase_date_ms = "1532945808000",original_purchase_date_pst = "2018-07-30 03N16N48
America/Los_Angeles", original_transaction_id = "1000000424240109", product_id = "com.baidu.yuedu10000001", purchase_date = "2018-07-30 11N59N29 Etc/GMT", purchase_date_ms = "1532951969000", purchase_date_pst = "2018-07-30 04N59N29 America/Los_Angeles", quantity = "1", transaction_id = "1000000424574503", unique_identifier =
"ad9e3730489447ade8bd574c806a80b7161eecbd", unique_vendor_identifier = "EF5BB5D5-2800-40FD-9B6F-
E3C41C19AD0D", version_external_identifier = "0",
web_order_line_item_id = "1000000039700780", },
status = 21006, //标识订阅过期 }
// 正常证书 validate response : {
auto_renew_product_id = "com.baidu.yuedu1010", auto_renew_status = 1, latest_receipt =
"ewoJInNpZ25hdHVyZSIgPuZy1zdGF0dXMiID0gIjAiOwp9" latest_receipt_info = { // 最后⼀一次续订的证书(server⽤用这个来判断)
bid = "com.baidu.yuedu", bvrs = "5.9.0",
expires_date = "1529998515000"
expires_date_formatted = "2018-06-26 07N35N15 Etc/GMT", expires_date_formatted_pst = "2018-06-26 00N35N15
America/Los_Angeles", is_in_intro_offer_period = "false", //打折促销类型 is_trial_period = "false", //免费试⽤用类型(只有⾸首次开通才为true,后
⾯面重复开通都false) item_id = "1403279424",
original_purchase_date = "2018-06-26 05N46N44 Etc/GMT", original_purchase_date_ms = "1529992004000",original_purchase_date_pst = "2018-06-25 22N46N44
America/Los_Angeles", original_transaction_id = "1000000410956777", product_id = "com.baidu.yuedu1010", purchase_date = "2018-06-26 07N30N15 Etc/GMT", purchase_date_ms = "1529998215000", purchase_date_pst = "2018-06-26 00N30N15 America/Los_Angeles", quantity = "1", transaction_id = "1000000410999787", unique_identifier =
"ad9e3730489447ade8bd574c806a80b7161eecbd", unique_vendor_identifier = "EF5BB5D5-2800-40FD-9B6F-
E3C41C19AD0D", web_order_line_item_id = "1000000039251964",
}, receipt = { // 当前请求证书的解析
bid = "com.baidu.yuedu", bvrs = "5.9.0", expires_date = "1529998515000", expires_date_formatted = "2018-06-26 07N35N15 Etc/GMT", expires_date_formatted_pst = "2018-06-26 00N35N15
America/Los_Angeles", is_in_intro_offer_period = "false",
is_trial_period = "false"
item_id = "1403279424", original_purchase_date = "2018-06-26 05N46N44 Etc/GMT", original_purchase_date_ms = "1529992004000",original_purchase_date_pst = "2018-06-25 22N46N44
America/Los_Angeles", original_transaction_id = "1000000410956777", product_id = "com.baidu.yuedu1010", purchase_date = "2018-06-26 07N30N15 Etc/GMT", purchase_date_ms = "1529998215000", purchase_date_pst = "2018-06-26 00N30N15 America/Los_Angeles", quantity = "1", transaction_id = "1000000411001173", unique_identifier =
"ad9e3730489447ade8bd574c806a80b7161eecbd", unique_vendor_identifier = "EF5BB5D5-2800-40FD-9B6F-
E3C41C19AD0D", version_external_identifier = "0",
web_order_line_item_id = "1000000039251964", },
status = 0, }
iOS7以后的新证书: {
environment = "Sandbox",
latest_receipt = "MIJKSgYJKoZIhvcNAQcCoIJKOzCCswyE5b/K5ez9E6huPkHuH+RnDVU9S7Yl ekH39wDP1xcN3O2jQRkmRfSbcG9i1lretoojbaMX+0HPGIIxUZc/5As2xei5Ca8 RY="
latest_receipt_info = [ { //ios7以后的每个证书会携带所有的⽀支付信息,包含各种类型⽐比如阅
读⾖豆,会员,⾃自动续费(1010) is_trial_period = "false",
original_purchase_date = "2018-03-08 03N05N31 Etc/GMT",
original_purchase_date_ms = "1520478331000",
original_purchase_date_pst = "2018-03-07 19N05N31 America/Los_Angeles",
original_transaction_id = "1000000381405130", product_id = "com.baidu.yuedu1001", purchase_date = "2018-03-08 03N05N31 Etc/GMT" purchase_date_ms = "1520478331000", purchase_date_pst = "2018-03-07 19N05N31
America/Los_Angeles", quantity = "1",
transaction_id = "1000000381405130", },
{
expires_date = "2018-06-26 07N49N38 Etc/GMT", expires_date_ms = "1529999378000", expires_date_pst = "2018-06-26 00N49N38
America/Los_Angeles", is_in_intro_offer_period = "false",
is_trial_period = "false", original_purchase_date = "2018-06-26 05N46N44 Etc/GMT" original_purchase_date_ms = "1529992004000",original_purchase_date_pst = "2018-06-25 22N46N44
America/Los_Angeles", original_transaction_id = "1000000410956777",
product_id = "com.baidu.yuedu1010", purchase_date = "2018-06-26 07N44N38 Etc/GMT", purchase_date_ms = "1529999078000", purchase_date_pst = "2018-06-26 00N44N38
America/Los_Angeles", quantity = "1",
transaction_id = "1000000411009485",
web_order_line_item_id = "1000000039252384", }
],
pending_renewal_info = [ {
auto_renew_product_id = "com.baidu.yuedu1010", auto_renew_status = "1"
original_transaction_id = "1000000410956777", product_id = "com.baidu.yuedu1010",
}
],
receipt = { adam_id = 0,
app_item_id = 0, application_version = "5.9.0", bundle_id = "com.baidu.yuedu", download_id = 0
in_app = [
Etc/GMT",
{
is_trial_period = "false", original_purchase_date = "2018-03-08 03N05N31
original_purchase_date_ms = "1520478331000",
original_purchase_date_pst = "2018-03-07 19N05N31 America/Los_Angeles",
original_transaction_id = "1000000381405130", product_id = "com.baidu.yuedu1001", purchase_date = "2018-03-08 03N05N31 Etc/GMT" purchase_date_ms = "1520478331000", purchase_date_pst = "2018-03-07 19N05N31
America/Los_Angeles", quantity = "1",
transaction_id = "1000000381405130", },
{
expires_date = "2018-06-26 07N49N38 Etc/GMT", expires_date_ms = "1529999378000",
expires_date_pst = "2018-06-26 00N49N38 America/Los_Angeles",
is_in_intro_offer_period = "false", is_trial_period = "false", original_purchase_date = "2018-06-26 05N46N44 Etc/GMT" original_purchase_date_ms = "1529992004000",original_purchase_date_pst = "2018-06-25 22N46N44
America/Los_Angeles", original_transaction_id = "1000000410956777",
product_id = "com.baidu.yuedu1010", purchase_date = "2018-06-26 07N44N38 Etc/GMT", purchase_date_ms = "1529999078000", purchase_date_pst = "2018-06-26 00N44N38
America/Los_Angeles", quantity = "1",
transaction_id = "1000000411009485",
web_order_line_item_id = "1000000039252384", }
], original_application_version = "1.0", original_purchase_date = "2013-08-01 07N00N00 Etc/GMT", original_purchase_date_ms = "1375340400000",original_purchase_date_pst = "2013-08-01 00N00N00
America/Los_Angeles", receipt_creation_date = "2018-06-26 07N44N40 Etc/GMT", receipt_creation_date_ms = "1529999080000",receipt_creation_date_pst = "2018-06-26 00N44N40
America/Los_Angeles", receipt_type = "ProductionSandbox",
request_date = "2018-06-26 07N45N03 Etc/GMT", request_date_ms = "1529999103799", request_date_pst = "2018-06-26 00N45N03 America/Los_Angeles", version_external_identifier = 0,
},
status = 0, }
注意:
latest_receipt_info = {
bid = "com.baidu.yuedu", bvrs = "5.9.0", expires_date = "1532595823000"
expires_date_formatted = "2018-07-26 09N03N43 Etc/GMT", expires_date_formatted_pst = "2018-07-26 02N03N43
America/Los_Angeles", is_in_intro_offer_period = "false",
is_trial_period = "false", item_id = "1416998263", original_purchase_date = "2018-06-26 05N46N44 Etc/GMT", original_purchase_date_ms = "1529992004000",original_purchase_date_pst = "2018-06-25 22N46N44
America/Los_Angeles", original_transaction_id = "1000000410956777", product_id = "com.baidu.yuedu2001", purchase_date = "2018-07-26 08N58N43 Etc/GMT", purchase_date_ms = "1532595523000", purchase_date_pst = "2018-07-26 01N58N43 America/Los_Angeles", quantity = "1", transaction_id = "1000000422921287", unique_identifier =
"ad9e3730489447ade8bd574c806a80b7161eecbd", unique_vendor_identifier = "EF5BB5D5-2800-40FD-9B6F-
E3C41C19AD0D", web_order_line_item_id = "1000000039656744",
}, receipt = {
bid = "com.baidu.yuedu", bvrs = "5.9.0",
expires_date = "1532595823000", expires_date_formatted = "2018-07-26 09N03N43 Etc/GMT", expires_date_formatted_pst = "2018-07-26 02N03N43
America/Los_Angeles", is_in_intro_offer_period = "false",
is_trial_period = "false"
item_id = "1416998263", original_purchase_date = "2018-06-26 05N46N44 Etc/GMT", original_purchase_date_ms = "1529992004000",original_purchase_date_pst = "2018-06-25 22N46N44
America/Los_Angeles", original_transaction_id = "1000000410956777", product_id = "com.baidu.yuedu2001", purchase_date = "2018-07-26 08N58N43 Etc/GMT", purchase_date_ms = "1532595523000", purchase_date_pst = "2018-07-26 01N58N43 America/Los_Angeles", quantity = "1", transaction_id = "1000000422923112", unique_identifier =
"ad9e3730489447ade8bd574c806a80b7161eecbd", unique_vendor_identifier = "EF5BB5D5-2800-40FD-9B6F-
E3C41C19AD0D", version_external_identifier = "0",
web_order_line_item_id = "1000000039656744", },
过期时间相同,⽀支付时间相同,是同⼀一次⽀支付,但是他的transaction_id却不不 同。
所以server不不能⽤用transaction_id来做为业务上的去重。
[图片上传失败...(image-43db27-1571314172360)]