Проверьте получение для In App purchase

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

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

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

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

спасибо

8 ответов


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

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

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

затем, где вы собираетесь начать запись транзакции на удаленном сервере, позвоните 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 post. (cURL является одним из возможных вариантов. YMMV. PHP.net есть сенсация!)

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

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


полный исходный код, а также размещенный пример реализации PHP доступен по адресу: http://www.chrismaddern.com/validate-app-store-iap-receipt-codes-online-tool/

надеюсь, это тебе поможет!


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

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

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

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

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

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

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


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

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


Я удивлен, что не нашел учебника Рэй Вендерлих здесь - просто спас мою жизнь. Проходит проверку квитанций без сервера (не рекомендуемое решение, но в любом случае сильно сделано).

http://www.raywenderlich.com/23266/in-app-purchases-in-ios-6-tutorial-consumables-and-receipt-validation


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

<?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


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

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

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

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

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

затем мы использовали CURL для публикации в песочнице и использовали json_decode в ответе.


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

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