iOS 自动续期订阅 恢复购买

 

 

https://blog.csdn.net/Kun__kun/article/details/115525030

 

恢复购买

内购有4种:消耗型项目,非消耗型,自动续期订阅,非续期订阅。 其中”非消耗型“和”自动续期订阅“需要提供恢复购买的功能,例如创建一个恢复按钮,不然审核很可能会被拒绝。

  1.  
    //调起苹果内购恢复接口
  2.  
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

“消耗型项目”和“非续期订阅”苹果不会提供恢复的接口,不要调用上述方法去恢复,否则有可能被拒。 “非续期订阅”也是“跨设备同步”的,所以原则上来说也需要提供恢复购买的功能,但需要依靠app自建的账户体系恢复,不能用上述苹果提供的接口。

恢复购买将为用户完成的每个事务创建一个新事务,基本上是为事务队列观察者重新播放历史记录。

事务(Transaction)

内购事务的观察者应尽早设置好,例如在程序启动后马上设置:

  1.  
    - (BOOL)application:(UIApplication *)application
  2.  
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
  3.  
    {
  4.  
      /* ... */
  5.  
      [[SKPaymentQueue defaultQueue] addTransactionObserver:observer];
  6.  
    }

完成事务要调用:

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

完成事务会告诉StoreKit你已经完成了购买所需的一切。未完成的事务将一直留在队列中,直到它们完成为止,每次启动应用程序时都会调用事务队列观察者,以便应用程序能够继续去完成未被完成的事务。你的应用需要完成每一笔交易,不管交易成功还是失败。 需要注意:在你完成一个事务之后,不应该再对这次交易做任何操作,例如交付产品或者验证交易是否有效等。如果还有工作要做,那证明你还没有准备好完成这个事务。应在所有必要的工作完成后,再调用完成事务的方法。

购买后的记录依据

对于iOS 7及以后的非消耗品和自动续期订阅,使用app收据作为你的持久记录。 对于iOS 7之前版本的非消耗品和自动续期订阅,请使用用户默认系统或iCloud保存持久记录。 对于非续期的订阅,请使用iCloud或你自己的服务器来保存持久记录。 对于消耗品,应用程序更新其内部状态以反映购买情况,但不需要保存持久记录,因为消耗品不会跨设备恢复或同步。

验证收据

应用程序收据包含用户购买的记录,由苹果公司以密码签署。 对于消耗型项目,信息在付款时添加到收据中,并保留在收据中,直到你完成交易。在你完成交易之后,该信息将在下一次更新收据时被删除——例如,下一次用户进行购买时。 所有其他类型的购买信息在付款时被添加到收据中,并无限期地保留在收据中。

收据的验证应该在服务端去做,这样更加安全。 自动续期订阅验证收据时必须要带上密钥。

获取receiptData:

  1.  
    // Load the receipt from the app bundle.
  2.  
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
  3.  
    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
  4.  
    if (!receiptData) { /* No local receipt -- handle the error. */ }
  5.  
    /* ... Send the receipt data to your server ... */

测试环境url:https://sandbox.itunes.apple.com/verifyReceipt 正式环境url:https://buy.itunes.apple.com/verifyReceipt 获取收据数据:

  1.  
    //先对receiptData用base64编码
  2.  
    NSString *receiptBase64 = [receiptData base64EncodedStringWithOptions:0];
  3.  
    //请求参数包含两个字段:“receipt-data”和”password“,其中”password“是自动续期订阅的密钥,其他类型的内购没有这个密钥就不会加这个参数。
  4.  
    NSDictionary *params = @{@"receipt-data":receiptBase64, @"password":secretKey};
  5.  
    //将params转成jsonData
  6.  
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:params
  7.  
    options:NSJSONWritingPrettyPrinted
  8.  
    error:nil];
  9.  
    //下面就是网络请求,例如
  10.  
    NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:url];
  11.  
    [req setHTTPMethod:@"POST"];
  12.  
    [req setHTTPBody:jsonData];
  13.  
    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
  14.  
    ...
解析收据: 请求成功后返回的数据类似这个格式:


  1.  
    {"status": , //如果收据有效,则为0,其他值表示错误
  2.  
    "receipt": ,
  3.  
    "latest_receipt": ,
  4.  
    "latest_receipt_info": , //只返回包含自动更新订阅的收据。这个键的值是一个包含所有应用程序内购买交易的数组。这排除了已经被你的应用标记为完成的消耗品的交易。
  5.  
    "latest_expired_receipt_info": ,
  6.  
    "pending_renewal_info": ,
  7.  
    "is-retryable": ,}
对于收据中每个字段的说明,参考苹果官方文档: https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html#//apple_ref/doc/uid/TP40010573-CH104-SW1

这里说明一下自动续期订阅的验证问题: latest_receipt_info中包含所有订阅的交易信息,这是一个数组,里面每个元素代表一次订阅交易,元素中有expires_date_ms的字段表示订阅的过期时间,purchase_date_ms表示订阅的购买时间,product_id表示订阅的产品id,is_trial_period表示是否是免费试用。 需要注意,latest_receipt_info中的元素没有特定的排序,我们应该先将latest_receipt_info中的元素按expires_date_ms升序排序,然后获取最后一个元素,这个元素就是最新的交易信息。 另外,收据的json解析有可能会出错,要注意错误处理。

订阅后联系苹果退款

订阅在购买时全额支付。用户只有联系苹果客服才能获得退款。例如,如果用户不小心购买了错误的产品,可以取消订阅,并发出全额或部分退款。 要检查购买是否已经被“Apple客户支持”取消,请在收据中查找cancel Date字段。如果字段包含日期,无论订阅的过期日期如何,购买都已取消。

自动续期订阅的免费试用(促销价)

假如订阅设定了促销价,例如免费试用,SKProduct对象的introductoryPrice属性会有值,这个属性包含了促销价的信息,开发者应该根据这个属性去显示促销的相关UI。

“非续期订阅”不同于”自动续期订阅“的地方

非续期订阅与自动续期订阅在几个关键方面有所不同。这些差异使你的应用程序具有灵活性,可以根据你的需要实现正确的行为,对于“非续期订阅”: 你的应用程序负责计算订阅有效的时间段,并确定需要向用户提供哪些内容。 你的应用程序负责检测订阅即将过期,并通过再次购买产品提示用户更新订阅。 你的应用程序负责在用户的所有设备提供订阅,并让用户恢复过去的购买。例如,大多数订阅由服务器提供,你的服务器需要一些机制来识别用户,并将订阅购买与购买它们的用户关联起来。

测试

在沙盒环境中自动续期订阅时限会缩短,便于测试:

实际时间测试时间
1周 3分钟
1个月 5分钟
3个月 15分钟
1年 1小时

测试订阅每天最多仅能自动续期 6 次。

审核

审核人员会用沙盒账号测试内购,所以在审核的时候,收据验证要用测试环境的url去验证,不然会因为验证失败而被拒绝。 推荐的做法是,验证收据时,如果status==21007,就用测试环境的url再次验证,如果status==21008,就用正式环境的url再次验证。

自动续期订阅需要做一个自动续期会员说明,这个说明放在app的内购页面中,并且在AppStoreConnect中的描述中也要写一次,不然也会被拒绝,怎么写,可以参考优酷,爱奇艺app的描述。

相关资料连接

https://help.apple.com/app-store-connect/#/devb57be10e7

https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction.html#//apple_ref/doc/uid/TP40008267-CH1-SW1

https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Introduction.html#//apple_ref/doc/uid/TP40010573-CH105-SW1

 

posted @ 2021-07-21 20:38  itlover2013  阅读(1090)  评论(0编辑  收藏  举报