检查自动更新订阅是不是过期

Posted

技术标签:

【中文标题】检查自动更新订阅是不是过期【英文标题】:Checking auto-renewable subscriptions for expiration检查自动更新订阅是否过期 【发布时间】:2016-12-24 17:35:29 【问题描述】:

我已经设置了一个沙盒用户,并在我的 iPhone 设备上成功地为他们订阅了为期一个月的自动续订订阅。如何检测用户的订阅是否已结束?

我有以下代码:

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

它最终会调用这个方法和逻辑:

- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue

    for (SKPaymentTransaction *transaction in queue.transactions) 
        if (transaction.transactionState == SKPaymentTransactionStateRestored) 
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            [self setSubscriptionActive]; // <-- Probably not the right way to restore subscriptions?
            return; // Return because we have successfully set the subscribed state of the app.
        
    
    [self purchase:self.validProduct]; // No valid transactions, so ask them to purchase.

我的问题是,鉴于我目前的逻辑,现在已经两个小时了,这个测试用户总是到达代码行,[self setSubscriptionActive];,因此我在他的测试帐户下支付的唯一款项总是返回SKPaymentTransactionStateRestored .我希望它现在到期according to the documentation from Table 3-1 (Subscription durations for testing)...所以现在我想知道,我做错了什么,和/或有人知道验证这个一个月/及时订阅是否有的正确方法是什么过期了?

我什至尝试按照他们的收据验证文章在 Apple 的沙盒服务器上对收据进行 JSON 查询。仔细查看这些数据,亲眼看看这一切有多糟糕:

"original_purchase_date" = "2013-08-01 07:00:00 Etc/GMT";
"original_purchase_date_ms" = 1375340400000;
"original_purchase_date_pst" = "2013-08-01 00:00:00 America/Los_Angeles";
"receipt_creation_date" = "2016-08-18 01:05:09 Etc/GMT";
"receipt_creation_date_ms" = 1471482309000;
"receipt_creation_date_pst" = "2016-08-17 18:05:09 America/Los_Angeles";
"receipt_type" = ProductionSandbox;
"request_date" = "2016-08-18 01:05:09 Etc/GMT";
"request_date_ms" = 1471482309971;
"request_date_pst" = "2016-08-17 18:05:09 America/Los_Angeles";

我看到了两个问题:

    这是第一次购买,但它显示了 original_purchase_date2013-08-01 07:00:00 Etc/GMT。我今天买了。这个时间距离 8 月 17 日还很远。这是非常不正确的。

    receipt_creation_date2016-08-18 01:05:09 Etc/GMTrequest_date2016-08-18 01:05:09 Etc/GMT...我必须在创建收据的瞬间发出网络请求。我假设因为request_date(就像这个垃圾API的大部分)没有记录它的有效互联网时间,所以你可以用它来比较(而不是本地时间)它和receipt_creation_date之间的增量时间。天哪,这真是一场噩梦……为什么会有人让任何人制作这样一个如此复杂、荒谬的后端系统?这绝对是可怕的。真可惜,因为 Apple 的其他 API 总体上都不错。

【问题讨论】:

【参考方案1】:

不要手动计算日期。根据Apple's Validate App Store Receipt,你应该使用expires_date

此密钥仅适用于自动更新订阅收据。使用此值来标识订阅续订或到期的日期,以确定客户是否应该有权访问内容或服务。验证最新收据后,如果最新续订交易的订阅到期日期是过去的日期,则可以安全地假定订阅已过期。

【讨论】:

【参考方案2】:

您从收据中获得 pending_renewal_info 数组,如下所示。

"pending_renewal_info" =     (
                
            "auto_renew_product_id" = "YOUR_IN_APP_ID";
            "auto_renew_status" = 0;
            "expiration_intent" = 1;
            "is_in_billing_retry_period" = 0;
            "original_transaction_id" = 1000000XXXXXXXXX;
            "product_id" = "XXXXX";
        ,
                
            "auto_renew_product_id" = YOUR_IN_APP_ID;
            "auto_renew_status" = 0;
            "expiration_intent" = 1;
            "is_in_billing_retry_period" = 0;
            "original_transaction_id" = 1000000398636152;
            "product_id" = "XXXXXXX";
        
    );

您应该检查 expiration_intent。如果 expiration_intent 为 1,则表示您的订阅包已过期。如果 expiration_intent 键在字典中不可用,则意味着您的包仍然有效。

希望对你有帮助。

【讨论】:

但是如何获得新的到期日期?【参考方案3】:

我找到了一个解决方案,因为我知道我的订阅可以使用一个月,因此我可以将 transaction.transactionDate 增加一个月并将其与 UTC 时间进行比较(顺便说一下,这里的一个好主意是获取 UTC 时间进程外,这样您就不会遇到用户通过设置系统时钟来规避订阅的情况):

- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue

    // Check all transactions for any that might be restoration candidates.
    for (SKPaymentTransaction *transaction in queue.transactions) 
        if (transaction.transactionState == SKPaymentTransactionStateRestored) 
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            NSCalendar *calendar = [NSCalendar currentCalendar];
            NSDate *expiration = [calendar dateByAddingUnit:NSCalendarUnitMonth value:1 toDate:transaction.originalTransaction.transactionDate options:0];
            if ([expiration earlierDate:self.currentUTCTime] == self.currentUTCTime) 
                [self setSubscriptionInterfaceActive:true];
                return;
            
        
    
    // There are no valid restorations, so we ask the user to subscribe here (this may obviously differ in your application as I am using a Purchase or Restore Subscription button in my app).
    [self setSubscriptionInterfaceActive:false];
    [self purchase:self.validProduct];

【讨论】:

此代码包含很多错误 + 您可能有不同到期时间的订阅。否决

以上是关于检查自动更新订阅是不是过期的主要内容,如果未能解决你的问题,请参考以下文章

无法使用 iOS 沙盒自动更新订阅测试订阅升级/降级

求 Oracle 大神指教,更具时间自动更新状态

iOS Testflight Autorenewable Subscription 的过期时间是不是被破坏?

从验证收据中检查自动续订订阅到期日期

如何更新自动更新订阅收据

自动更新订阅:检测差距