检查自动续订订阅到期

时间:2016-08-17 22:23:12

标签: ios objective-c subscription storekit

我已经设置了一个沙箱用户并成功订阅了我的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) ...所以现在我想知道,我做错了什么,和/或有没有人知道正确的方法是验证这一个月/是否及时订阅已过期?

我甚至试图让JSON在Apple的收据验证文章后查询Apple的沙箱服务器上的收据。仔细查看这些数据,亲自了解这一切是如何破坏的:

"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";

我看到了两个问题:

  1. 这是第一次购买,但它显示original_purchase_date 2013-08-01 07:00:00 Etc/GMT。我今天买了它。这个时间远不及8月17日。这非常不正确。

  2. receipt_creation_date2016-08-18 01:05:09 Etc/GMTrequest_date2016-08-18 01:05:09 Etc/GMT ...我必须在创建收据的瞬间完成网络请求。我假设,因为request_date(与大部分垃圾API一样)没有记录其有效的互联网时间,因此您可以使用它来比较它与{之间的增量时间(而不是当地时间) {1}}。上帝,这是一场噩梦......为什么有人会让任何人制造出如此复杂,荒谬的后端系统?这绝对是可怕的。这是一种耻辱,因为Apple的其他API一般都很好。

3 个答案:

答案 0 :(得分:3)

不要手动计算日期。根据{{​​3}},您应该使用expires_date

  

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

答案 1 :(得分:2)

我找到了一个解决方案,因为我知道我的订阅有效期为一个月,因此我可以将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];
}

答案 2 :(得分:1)

您会从下面的收据中获得 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 键在词典中不可用,则意味着您的背包仍然有效。

我希望这会对您有所帮助。