8

我最近更新了一个应用程序,可以在应用程序购买中使用。以前的版本(付费但没有应用内购买)是 1.0,当前版本是 1.1。

由于应用内购买基本上解锁了所有功能(包括在付费版本 1.0 中),我想要一种方法让最初下载版本 1.0 的用户在按下我的恢复购买按钮时进行升级。

为此,我首先尝试恢复购买,如果响应:

- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue

如果这为我提供了一个事务计数为 0 的队列,我会检查收据以查看安装的原始版本是否为 1.0。

获取收据的代码是根据 Apple 的文档

- (void)tryRestoreFromOriginalPurchase
{
    // Load the receipt from the app bundle
    NSError *error;
    NSData  *receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];

    if (receipt == nil) {
        [self restoreFromOriginalVersionWithReceipt:nil];
        return;
    }

    // Create the JSON object that describes the request
    NSDictionary *requestContents = @{@"receipt-data": [receipt base64EncodedStringWithOptions:0]};
    NSData       *requestData     = [NSJSONSerialization dataWithJSONObject:requestContents options:0 error:&error];

    if (!requestData) {
        [self restoreFromOriginalVersionWithReceipt:nil];
        return;
    }

    // Create a POST request with the receipt data
    NSURL *storeURL = [NSURL URLWithString:@"https://buy.itunes.apple.com/verifyReceipt"];
    NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];

    [storeRequest setHTTPMethod:@"POST"];
    [storeRequest setHTTPBody:requestData];

    // Make a connection to the iTunes Store on a background queue
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    [NSURLConnection sendAsynchronousRequest:storeRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        if (!connectionError) {
            NSError      *error;
            NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];

            if (jsonResponse) [self restoreFromOriginalVersionWithReceipt:jsonResponse];
            else              [self restoreFromOriginalVersionWithReceipt:nil];
        } else {
            [self restoreFromOriginalVersionWithReceipt:nil];
        }
    }];
}

然后调用以下方法:

- (void)restoreFromOriginalVersionWithReceipt:(NSDictionary *)receipt
{
    if (receipt == nil) {
        // CALL METHOD TO HANDLE FAILED RESTORE
    } else {
        NSInteger status = [[receipt valueForKey:@"status"] integerValue];

        if (status == 0) {
            NSString *originalApplicationVersion = [[receipt valueForKey:@"receipt"] valueForKey:@"original_application_version"];

            if (originalApplicationVersion != nil && [originalApplicationVersion isEqualToString:@"1.0"]) {
                // CALL METHOD TO HANDLE SUCCESSFUL RESTORE
            } else {
                // CALL METHOD TO HANDLE FAILED RESTORE
            }
        } else {
            // CALL METHOD TO HANDLE FAILED RESTORE
        }
    }
}

现在这行不通了。当有人安装 1.1 版并点击恢复购买时,它会在不应该的情况下成功恢复。

我刚刚意识到在我的 Info.plist 中,我的 CFBundleShortVersionString 是 1.1,但我的 CFBundleVersion 是 1.0。

这可能是一个非常愚蠢的问题,但是即使更新版本为 1.1,收据是否提供了 original_application_version 1.0(由于错误的 CFBundleVersion)?

因此,如果我发布一个新的更新,并修正为 1.2 版(对于 CFBundleShortVersionString 和 CFBundleVersion),问题会得到解决吗?

- 更新 -

所以我刚刚上传了一个新版本到应用商店,CGBundleVersion 和 CFBundleShortVersionString 都等于 1.2。但是,我仍然面临同样的问题 - 首次下载 1.2 版并点击恢复购买的用户正在免费升级(由于上述收据检查)。看来 original_application_version 总是要到 1.0。

注意:我正在使用以前未下载过该应用程序的新 iTunes 帐户下载该应用程序。

这是我从应用商店安装然后尝试通过 Xcode 获取收据时的收据

2014-08-27 08:46:42.858 AppName[4138:1803] {
    environment = Production;
    receipt =     {
        "adam_id" = AppID;
        "application_version" = "1.0";
        "bundle_id" = "com.CompanyName.AppName";
        "download_id" = 94004873536255;
        "in_app" =         (
        );
        "original_application_version" = "1.0";
        "original_purchase_date" = "2014-08-26 22:30:49 Etc/GMT";
        "original_purchase_date_ms" = 1409092249000;
        "original_purchase_date_pst" = "2014-08-26 15:30:49 America/Los_Angeles";
        "receipt_type" = Production;
        "request_date" = "2014-08-26 22:46:42 Etc/GMT";
        "request_date_ms" = 1409093202544;
        "request_date_pst" = "2014-08-26 15:46:42 America/Los_Angeles";
    };
    status = 0;
}

有什么想法吗?

4

2 回答 2

19

我偶然发现了同样的问题 - 我将我的应用从付费转换为免费增值,并尝试original_application_version在应用收据中使用来决定为谁解锁新的免费增值功能。我也一样,失败了。

但是,我发现我使用original_application_version不正确。这个名字误导我认为这个字符串对应于应用程序的版本号。在 iOS 上,它没有。original_application_version实际上是应用程序的内部版本号。

原始应用程序版本

这对应于最初购买时 Info.plist 文件中的CFBundleVersion(在 iOS 中)或 CFBundleShortVersionString(在 macOS 中)的值。在沙盒环境中,该字段的值始终为“1.0”。

来源:https ://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html

我认为这可能是你得到一个你不期望的数字的原因。

不过,正如您最后所做的那样,使用original_purchase_date是一种可靠的选择。

于 2015-06-04T09:51:22.993 回答
7

自从提出这个问题以来已经有一段时间了,但它提出了一些非常重要的观点:

收据中的原始应用版本字段对应的是 CFBundleVersion,而不是 CFBundleShortVersionString。在沙盒(开发人员构建)环境中,值字符串始终为“1.0”。

请注意,从付费应用程序转换为免费增值应用程序时,如果原始(付费版本)用户卸载该应用程序,然后从 iTunes 重新安装,将没有本地收据。如果该用户从未进行过应用内购买,则调用SKPaymentQueue restoreCompletedTransactions不会导致下载新收据。SKReceiptRefreshRequest在这种情况下,您需要使用而不依赖于恢复功能来请求收据刷新。

于 2017-01-19T18:51:24.553 回答