Не удается получить исходную версию приложения, установленную пользователем (проверка получения)?

У меня есть приложение, которое я недавно обновил для работы с покупками приложений. Предыдущая версия (платная, но без покупок в приложении) была 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.

Это может быть действительно глупый вопрос, но указывает ли квитанция original_application_version 1.0 (из-за неправильного CFBundleVersion), даже если обновление имеет версию 1.1?

Итак, если я выпущу новое обновление с исправленной версией 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;
}

Есть предположения?


person kash    schedule 26.08.2014    source источник
comment
В случае, если кто-то пройдет это и у него возникнет та же проблема, я не смог заставить приведенный выше код работать. Вместо этого я получил желаемый результат, сверившись с original_purchase_date.   -  person kash    schedule 09.09.2014
comment
Я пробовал этот код, но каждый раз он говорит, что квитанция = ноль.   -  person NCFUSN    schedule 21.12.2014
comment
@NCF повезло с этим?   -  person strangetimes    schedule 08.10.2016
comment
@sheefy, не могли бы вы сказать, что даже сейчас вам удобнее использовать original_date вместо номера версии? Я собираюсь сделать то же самое, ваш код достаточно актуален для повторного использования?   -  person strangetimes    schedule 08.10.2016
comment
@NCFUSN Тестируете локально, запуская из Xcode? Если это так, квитанция будет нулевой IIRC. Создайте сборку TestFlight, и вы получите квитанцию   -  person Kartick Vaddadi    schedule 09.09.2017


Ответы (2)


Я наткнулся на ту же проблему — я преобразовал свое приложение из платного в бесплатное и попытался использовать original_application_version в квитанции приложения, чтобы решить, для кого разблокировать новые функции бесплатного доступа. У меня тоже не получилось.

Однако я обнаружил, что неправильно использовал original_application_version. Название ввело меня в заблуждение, заставив думать, что эта строка соответствует номеру версии приложения. На iOS этого нет. original_application_version — это номер сборки приложения.

Исходная версия приложения

Это соответствует значению CFBundleVersion (в iOS) или CFBundleShortVersionString (в macOS) в файле Info.plist при первоначальной покупке. В среде песочницы значение этого поля всегда равно «1,0».

Источник: https://developer.apple.com/library/archive/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html

Я думаю, что это может быть причиной того, что вы получаете число, которого не ожидаете.

Однако использование original_purchase_date, как вы сделали в конце, является надежной альтернативой.

person Andrew Wei    schedule 04.06.2015
comment
Я также могу подтвердить, что original_application_number — это номер сборки исходной версии, который практически бесполезен для определения фактической исходной версии. Поэтому, когда я перешел на freemium, я изменил номера своих сборок на префикс с номером версии. Таким образом, для версии 2.1.5 сборка 1 будет 2.1.5.1. Pre-freemium версии всегда имели однозначный номер сборки, поэтому теперь было легко отличить оригинальных клиентов от новых. - person Murray Sagal; 03.12.2016

Прошло некоторое время с тех пор, как этот вопрос был задан, но он поднимает некоторые очень важные моменты:

Исходное поле версии приложения в квитанции соответствует CFBundleVersion, а не CFBundleShortVersionString. В среде песочницы (сборка для разработчиков) строка значения всегда "1.0".

Обратите внимание, что при переходе с платного приложения на бесплатное, если пользователь оригинальной (платной версии) удалит приложение, а затем переустановит его из iTunes, локальной квитанции не будет. Вызов SKPaymentQueue restoreCompletedTransactions не приведет к загрузке новой квитанции, если этот пользователь никогда не совершал покупки в приложении. В этой ситуации вам нужно запросить обновление квитанции с помощью SKReceiptRefreshRequest, а не полагаться на функцию восстановления.

person Swud    schedule 19.01.2017