Подтвердить что ты не робот

Проверить получение для покупки приложения

Я несколько раз занимаюсь покупками приложений в течение нескольких дней, все работает нормально до тех пор, пока я не попытаюсь проверить квитанцию ​​с магазином приложений, так как я постоянно возвращаю неверный статус.

Я передаю данные квитанции на свой PHP-сервер, а затем отправляю оттуда в хранилище приложений, и как только я получу правильный ответ, я намерен добавить данные квитанции в свою базу данных.

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

В принципе, мне интересно, будет ли кто-то, у кого есть проверка валидации квитанций, будет делиться своим кодом, поскольку я никуда не буду.

Спасибо

4b9b3361

Ответ 1

Во-первых, в опубликованном коде есть несколько опечаток. Попробуй это. (Отказ от ответственности: Рефакторинг и др. Оставлены в качестве упражнения для читателей!)

- (BOOL)verifyReceipt:(SKPaymentTransaction *)transaction {
    NSString *jsonObjectString = [self encode:(uint8_t *)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];      
    NSString *completeString = [NSString stringWithFormat:@"http://url-for-your-php?receipt=%@", jsonObjectString];               
    NSURL *urlForValidation = [NSURL URLWithString:completeString];       
    NSMutableURLRequest *validationRequest = [[NSMutableURLRequest alloc] initWithURL:urlForValidation];              
    [validationRequest setHTTPMethod:@"GET"];         
    NSData *responseData = [NSURLConnection sendSynchronousRequest:validationRequest returningResponse:nil error:nil];  
    [validationRequest release];
    NSString *responseString = [[NSString alloc] initWithData:responseData encoding: NSUTF8StringEncoding];
    NSInteger response = [responseString integerValue];
    [responseString release];
    return (response == 0);
}

- (NSString *)encode:(const uint8_t *)input length:(NSInteger)length {
    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    NSMutableData *data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
    uint8_t *output = (uint8_t *)data.mutableBytes;

    for (NSInteger i = 0; i < length; i += 3) {
        NSInteger value = 0;
        for (NSInteger j = i; j < (i + 3); j++) {
            value <<= 8;

            if (j < length) {
                value |= (0xFF & input[j]);
            }
        }

        NSInteger index = (i / 3) * 4;
        output[index + 0] =                    table[(value >> 18) & 0x3F];
        output[index + 1] =                    table[(value >> 12) & 0x3F];
        output[index + 2] = (i + 1) < length ? table[(value >> 6)  & 0x3F] : '=';
        output[index + 3] = (i + 2) < length ? table[(value >> 0)  & 0x3F] : '=';
    }

    return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
}

Вы можете сделать эти внутренние методы классу, который обрабатывает ваши сообщения SKPaymentTransactionObserver:

@interface YourStoreClass (Internal)
- (BOOL)verifyReceipt:(SKPaymentTransaction *)transaction;
- (NSString *)encode:(const uint8_t *)input length:(NSInteger)length;
@end

Примечание. Для обработки кодировки base64 вы можете использовать что-то вроде libcrypto, но затем вы смотрите на ограничения на экспорт и дополнительные шаги в момент утверждения приложения. Но я отвлекаюсь...

Затем, когда вы намереваетесь начать запись транзакции на своем удаленном сервере, вызовите verifyReceipt: с вашей транзакцией и убедитесь, что она возвращается положительно.

Между тем, на вашем сервере, здесь есть супер-урезанный PHP для обработки вещей:

$receipt = json_encode(array("receipt-data" => $_GET["receipt"]));
// NOTE: use "buy" vs "sandbox" in production.
$url = "https://sandbox.itunes.apple.com/verifyReceipt";
$response_json = call-your-http-post-here($url, $receipt);
$response = json_decode($response_json);

// Save the data here!

echo $response->status;

В случае, когда call-your-http-post-here - ваш любимый механизм HTTP-сообщений. ( cURL - один из возможных вариантов. YMMV. PHP.net имеет совок!)

Одна вещь, которая меня немного беспокоит, - это длина полезной нагрузки в URL-адресе, идущем из приложения на сервер (через GET). Я забываю, есть ли там длина вопроса в RFC. Возможно, это нормально, или, возможно, это зависит от сервера. (Читатели: Пособие приветствуется в этой части!)

Также может возникнуть некоторая ошибка при создании синхронного запроса. Возможно, вы захотите опубликовать его асинхронно и поместите ol ' UIActivityIndicatorView или другой HUD. Дело в том, что вызов initWithData: encoding: занимает время loooooong для меня. Несколько секунд, что является небольшой вечностью в iPhone на земле (или где-нибудь еще в Интернете, если на то пошло). Может показаться какой-то неопределенный индикатор прогресса.

Ответ 3

Для тех, кто задается вопросом, как обращаться с ошибками соединения или проверки, которые могут возникнуть при использовании модели сервера In-App-Purchase. Проверка валидации гарантирует, что транзакция будет завершена и успешна. Вы не хотите делать это с iPhone, потому что не можете доверять телефону пользователя.

  • Пользователь инициирует покупку в приложении
  • Когда приложение завершено, приложение запрашивает ваш сервер для проверки
  • Вы подтверждаете квитанцию ​​с Apple: если она действительна, вы можете выполнить любое действие, связанное с покупкой (разблокировать/доставить контент, зарегистрировать подписку...)
  • Приложение удаляет транзакцию из очереди (finishTransaction)

Если сервер не работает, вы не должны завершать транзакцию, но отображаете пользователю сообщение "недоступность".

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions

будет вызываться снова позже.

Но, если вы обнаружите, что квитанция недействительна, вы должны завершить связанную транзакцию. Если нет, у вас могут быть дополнительные транзакции, живущие вечно в очереди транзакций. Это означает, что каждый раз, когда ваше приложение запускается, paymentQueue: updatedTransaction: будет вызываться один раз за транзакцию...

В моих приложениях проверка чека выполняется через веб-службу, возвращая код ошибки в случае недопустимой квитанции. Поэтому необходим внешний сервер. Если пользователю каким-то образом удается пропустить проверку валидации (путем приведения в действие ответа "успех" веб-службы), он не сможет разблокировать функциональность контента/доступа, потому что у сервера нет следа покупки.

Ответ 4

После долгого боя с этим я наконец нашел список статусных кодов в документации Apple, включая страшный 21002 (который "Данные в свойстве данных квитанции были искажены" ). Хотя я видел сообщения о других кодах статуса, не включенных в этот список, я до сих пор не видел ничего, кроме того, что Apple задокументировала. Обратите внимание, что эти коды действительны только для автоматического возобновления подписки, а не для других видов покупок в приложении (или, соответственно, в документе).

Этот документ можно найти здесь.

Ответ 6

Вы должны отправить квитанцию ​​ в качестве файла на ваш сервер PHP. На вашей стороне PHP вы можете использовать этот script для проверки:

<?php

$path = 'receipt'; // $_FILE['receipt-data']["tmp_name"];
$receipt = file_get_contents($path);

$json['receipt-data'] = base64_encode($receipt);

$post = json_encode($json);

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,"https://buy.itunes.apple.com/verifyReceipt");
curl_setopt($ch, CURLOPT_POST,1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
$result=curl_exec ($ch);

curl_close ($ch);

?>

https://gist.github.com/eduardo22i/9adc2191f71ea612a7d071342e1e4a6f

Ответ 7

Просто, чтобы открыть это снова и добавить мои 2-центов взамен для получения данных этих форм для информации.

Я только что установил службу IAP в своем приложении и столкнулся с той же ошибкой 21002. Я обнаружил, что 21002 происходит, когда либо почта на ваш сервер PHP пуста (поэтому HTTP-запрос в хранилище приложений пуст) или неправильно отформатирован. Чтобы работать с нами, на стороне iPhone мы установили данные post в NSString как закодированные base64, а затем отправили их на наш сервер в качестве HTTP-запроса.

Затем на нашем сервере мы запустили его и запустили массив и json-ed. Вот так:

$receipt = json_encode(array("receipt-data"=>$_POST['receipt-data']));

Вы заметите, что это то же самое, что и выше, за исключением того, что мы используем POST вместо GET. Личное предпочтение действительно.

Затем мы использовали CURL для размещения его в песочнице и использовали json_decode для ответа.

Ответ 8

Это отличная библиотека, которая делает все, что нужно каждому по этому вопросу:

https://github.com/aporat/store-receipt-validator

Это выходит за рамки и подтверждает:

  • Itunes
  • Магазин игр
  • Amazon App Store

Я надеюсь, что это помогает кому-то еще, как помогает мне.

Ответ 9

Если вы получаете нулевые ответы или коды ошибок, например 21002, попробуйте добавить эти строки. Если вы проверили кодовые ошибки, это ошибка сертификата SSL...

curl_setopt ($curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($curl_handle, CURLOPT_SSL_VERIFYPEER, 0);