ios 如何检查应用内购买自动续订订阅是否有效

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5120177/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 19:01:41  来源:igfitidea点击:

How to check In App Purchase Auto Renewable Subscription is valid

iphoneobjective-ciosin-app-purchasesubscription

提问by Adam Swinden

I'm looking to implement the new Auto Renewable subscriptions using In App purchase but I am unsure how or when to check if the user is currently subscribed. My understanding is that when the user initially subscribes the app can use the purchase date along with the subscription date to calculate how long their subscription would last. What happens after this date has passed? How do we check if the user has auto renewed or cancelled?

我希望使用应用内购买来实施新的 Auto Renewable 订阅,但我不确定如何或何时检查用户当前是否已订阅。我的理解是,当用户最初订阅时,应用程序可以使用购买日期和订阅日期来计算他们的订阅将持续多长时间。此日期过后会发生什么?我们如何检查用户是否已自动续订或取消?

If I use restoreCompletedTransactionsto get a transaction and receipt for each renewal the user will be prompted to enter their iTunes password. Does this mean that if they have bought a 7 day subscription they will have to enter their password every 7 days when the app checks if the subscription is still valid?

如果我用来restoreCompletedTransactions为每次续订获取交易和收据,系统将提示用户输入他们的 iTunes 密码。这是否意味着如果他们购买了 7 天订阅,他们将必须每 7 天在应用程序检查订阅是否仍然有效时输入他们的密码?

采纳答案by Dobes Vandermeer

IF you want to check on it from a web server, you ping their API and it returns the status of the auto-renewable subscription and info about the last payment. link

如果您想从 Web 服务器检查它,您可以 ping 他们的 API,它会返回自动续订订阅的状态和有关上次付款的信息。关联

If you are on the device then you probably have to call restoreCompletedTransactions which I guess asks for the password.

如果您在设备上,那么您可能必须调用 restoreCompletedTransactions ,我猜它会要求输入密码。

I don't see any other method. I suppose from the device you could verify the subscription by contacting the same web service used on the server side? I don't know how the pros and cons of that.

我没有看到任何其他方法。我想从设备上,您可以通过联系服务器端使用的相同 Web 服务来验证订阅吗?我不知道这样做的利弊如何。

回答by Clover03ti05

Today, I have trouble with this problem.

今天,我遇到了这个问题。

Follow Apple dochere, I used this way to check subscription is expired or not. My idea: user APPLE REST API response: (request time + expired time) to check expired or not

按照这里的Apple 文档,我用这种方式检查订阅是否过期。我的想法:用户APPLE REST API响应:(请求时间+过期时间)检查是否过期

+ (BOOL)checkInAppPurchaseStatus
{
    // Load the receipt from the app bundle.
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
    if (receipt) {
        BOOL sandbox = [[receiptURL lastPathComponent] isEqualToString:@"sandboxReceipt"];
        // Create the JSON object that describes the request
        NSError *error;
        NSDictionary *requestContents = @{
                                          @"receipt-data": [receipt base64EncodedStringWithOptions:0],@"password":@"SHARE_SECRET_CODE"
                                          };
        NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
                                                              options:0
                                                                error:&error];

        if (requestData) {
            // Create a POST request with the receipt data.
            NSURL *storeURL = [NSURL URLWithString:@"https://buy.itunes.apple.com/verifyReceipt"];
            if (sandbox) {
                storeURL = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
            }
            NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
            [storeRequest setHTTPMethod:@"POST"];
            [storeRequest setHTTPBody:requestData];

            BOOL rs = NO;
            //Can use sendAsynchronousRequest to request to Apple API, here I use sendSynchronousRequest
            NSError *error;
            NSURLResponse *response;
            NSData *resData = [NSURLConnection sendSynchronousRequest:storeRequest returningResponse:&response error:&error];
            if (error) {
                rs = NO;
            }
            else
            {
                NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:resData options:0 error:&error];
                if (!jsonResponse) {
                    rs = NO;
                }
                else
                {
                    NSLog(@"jsonResponse:%@", jsonResponse);

                    NSDictionary *dictLatestReceiptsInfo = jsonResponse[@"latest_receipt_info"];
                    long long int expirationDateMs = [[dictLatestReceiptsInfo valueForKeyPath:@"@max.expires_date_ms"] longLongValue];
                    long long requestDateMs = [jsonResponse[@"receipt"][@"request_date_ms"] longLongValue];
                    NSLog(@"%lld--%lld", expirationDateMs, requestDateMs);
                    rs = [[jsonResponse objectForKey:@"status"] integerValue] == 0 && (expirationDateMs > requestDateMs);
                }
            }
            return rs;
        }
        else
        {
            return NO;
        }
    }
    else
    {
        return NO;
    }
}

Hope this help.

希望这有帮助。

回答by tikhop

Better to use a local solution before making any calls to the Apple api. Every time the app runs it's good a good practice to validate the local receipt and if you need to check if an user has the active subscription, you can first retrieve the purchases from the local receipt and find out is the purchase is still active for today.

在对 Apple api 进行任何调用之前,最好使用本地解决方案。每次应用程序运行时,验证本地收据是一个很好的做法,如果您需要检查用户是否有活动订阅,您可以先从本地收据中检索购买,并找出今天的购买是否仍然有效.

I have implemented a small library written in Swiftto simplify to work with In-App Receipt locally. You can easily fetch the object that represents the receipt (InAppReceipt) and retrieve an active purchase/all purchases.

我已经实现了一个编写的小型库,Swift以简化在本地使用应用内收据的工作。您可以轻松获取代表收据 ( InAppReceipt)的对象并检索活动购买/所有购买。

Feel free to use. Github link

随意使用。Github 链接

Here is an example of solving your problem:

以下是解决您的问题的示例:

import TPInAppReceipt

do {
    let receipt = try InAppReceiptManager.shared.receipt()

    //retrive active auto renewable subscription for a specific product and date
    let purchase = receipt.activeAutoRenewableSubscriptionPurchases(ofProductIdentifier: "ProductName", forDate: Date())

    //retrive all auto renewable subscription purchases for a specific product
    let allAutoRenewableSubscriptionPurchases = receipt.purchases(ofProductIdentifier: "productName").filter({ return ##代码##.isRenewableSubscription })
} catch {
    print(error)
}

回答by Peter B. Kramer

I am starting a campaign around this issue. Here is my observation and campaign:

我正在围绕这个问题发起一场运动。这是我的观察和活动:

Upon auto-renewal, the App Store calls the paymentQueueand posts a transaction. The transaction is posted with transaction.transactionState==SKPaymentTransactionStateRestored.

自动续订后,App Store 会调用paymentQueue并发布交易。交易以 过帐transaction.transactionState==SKPaymentTransactionStateRestored

The issue is that unfortunately this gets posted only to one device. A second device does not get the posting. Therefore, to detect the auto-renewal, or rather to detect the lack of an autorenewal and deny the device a continuing subscription, you have to do a restoreCompletedTransactionor "http post a 64-bit encoded JSON containing the last transaction". If the former, the user needs to give their password; that's intrusive - as you have pointed out above. If the latter, lots of additional coding is required. So, my question is...why doesn't StoreKithave a command:

问题是不幸的是,这只会发布到一台设备上。第二个设备没有得到该张贴。因此,要检测自动续订,或者更确切地说是检测缺少自动续订并拒绝设备继续订阅,您必须执行restoreCompletedTransaction或“http 发布包含最后一笔交易的 64 位编码 JSON”。如果是前者,用户需要提供他们的密码;这是侵入性的 - 正如你在上面指出的那样。如果是后者,则需要大量额外的编码。所以,我的问题是……为什么没有StoreKit命令:

(does not exist) - [[SKPaymentQueue defaultQueue] restoreAttachedTransactions:(NSArray *)transactions];

(不存在) - [[SKPaymentQueue defaultQueue] restoreAttachedTransactions:(NSArray *)transactions];

This command would flow just like a restoreCompletedTransactionsbut it would only restore the attached transactions and, most importantly, it would not require log-in by the user. It has the same security protection as the "http post a 64-bit encoded JSON containing the last transaction" and it allows the entire In App Purchase process to be done in StoreKitrather than requiring web posting code.

这个命令会像 a 一样流动,restoreCompletedTransactions但它只会恢复附加的交易,最重要的是,它不需要用户登录。它具有与“http 发布包含最后一笔交易的 64 位编码 JSON”相同的安全保护,并且它允许完成整个应用内购买过程,StoreKit而不需要网络发布代码。

If this makes sense to you, please suggest how to get this to Apple....thanks.

如果这对您有意义,请建议如何将其发送给 Apple....谢谢。