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

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

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

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

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

благодаря

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

- (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-сообщений. ( cURL – один из возможных вариантов. YMMV. PHP.net имеет совок!)

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

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

Полный исходный код, а также размещенный пример реализации 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: будет вызываться один раз за транзакцию …

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

После долгого боя с этим я наконец нашел список статусов в документации Apple, включая страшный 21002 (который «Данные в свойстве данных квитанции были искажены»). Хотя я видел сообщения о других кодах статуса, не включенных в этот список, я до сих пор не видел ничего, кроме того, что 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-запрос в хранилище приложений пуст) или неправильно отформатирован. Чтобы заставить нас работать, на стороне iPhone мы установили данные post в NSString как закодированные base64, а затем отправили их на наш сервер в виде HTTP-запроса.

Затем на нашем сервере мы вложили его и массировали, и json-ed. Как это:

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

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

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

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

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