Failed to get the original version of the application that the user installed (validation confirmation)?

I have an app that I recently updated to work in apps. The previous version (paid but no in-app purchases) was 1.0 and the current version is 1.1.

As an in-app purchase substantially unlocks all the features (that were included in the paid 1.0 version), I need a way for users who originally downloaded version 1.0 to upgrade if they clicked my buy button.

To do this, I will try to restore purchases first, and if the answer is:

- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue

      

If this gives me a queue with 0 transactions, I check the receipt to check if the original version 1.0 was installed.

Receipt code matches Apple documentation

- (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];
        }
    }];
}

      

Then the following method is called:

- (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
        }
    }
}

      

Now it doesn't work. When someone installs version 1.1 and taps restores purchases, it restores successfully when it shouldn't.

I just realized that in my Info.plist my CFBundleShortVersionString is 1.1, but my CFBundleVersion is 1.0.

It might be a very stupid question, but is it a receipt providing original_application_version 1.0 (due to incorrect CFBundleVersion), although the 1.1 update?

So, if I release a new update with a fixed version 1.2 (for CFBundleShortVersionString and CFBundleVersion), will the problem be resolved?

- UPDATE -

So, I just uploaded the new version to the app store with CGBundleVersion and CFBundleShortVersionString set to 1.2. However, I still face the same problem: users downloading version 1.2 for the first time and using restore purchases are updated for free (due to the check check outlined above). It seems original_application_version always reaches 1.0.

Note. I am downloading the application under a new iTunes account that has not previously downloaded the application.

Here is the receipt I get if I install it from the app store and then try to get the receipt through 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;
}

      

Any thoughts?

+3


source to share


2 answers


I stumbled upon the same problem - I converted my app from paid to freemium and tried to use the original_application_version

app in the receipt to decide what the new freemium features need to be unlocked for. I wasn't successful either.

However, I found out that I was using incorrectly original_application_version

. This name was misleading me into thinking that this line corresponds to the version number of the application. Is not. original_application_version

is actually a string .



I think this may be the reason why you are getting a number that you are not expecting.

Using original_purchase_date

, as at the end, is a reliable alternative.

+8


source


It's been a while since this question was asked, but it brings up some very important points:

The original application version field on the receipt matches CFBundleVersion, not CFBundleShortVersionString. In a sandbox environment (developer), the value string is always "1.0".



Please note that when converting from a paid app to freemium, if the original (paid version) user uninstalls the app and then reinstalls from iTunes, there will be no local retrieval. The call SKPaymentQueue restoreCompletedTransactions

will not download a new receipt if that user has never made an in-app purchase. In this situation, you need to ask to update the receipt with help SKReceiptRefreshRequest

and not rely on recovery functions.

+2


source







All Articles