Pergunta

Eu tenho jogado ao redor com em compras de aplicativos para alguns dias, tudo funciona bem até o ponto onde eu tentar validar o recibo com a App Store, como eu estou constantemente recebendo de volta um status inválido.

Eu estou passando os dados de recibo para o meu servidor PHP, em seguida, encaminhar a partir daí para a App Store e uma vez que recebo uma resposta válida tenho a intenção de adicionar os dados de recibo para o meu banco de dados.

O guia de programação loja kit e as referências da classe são menos do que inútil para esta área particular como eles realmente não lhe dar qualquer tipo de exemplo, eu encontrei um útil artigo que me ajudou um pouco, mas algo ainda está errado.

Basicamente, eu estou querendo saber se alguém que tem o recebimento de validação de trabalho estariam dispostos a compartilhar seu código como eu estou chegando a lugar nenhum.

Graças

Foi útil?

Solução

Em primeiro lugar, existem alguns erros no código postado. Tente isto. (Disclaimer:.! Refatoração et al é deixada como um exercício para o público)

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

Você pode fazer estes métodos internos sobre a classe que lida com a sua SKPaymentTransactionObserver mensagens:

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

Nota: poderia usar algo como libcrypto para base64 codificação punho, mas então você está olhando para as restrições à exportação e medidas adicionais no tempo de aprovação de aplicativos. Mas estou divagando ...

Então, onde quer que você pretende pontapé de saída a gravação da transação em seu servidor remoto, chamada verifyReceipt: com sua transação e verifique se ele volta positivo

.

Enquanto isso, em seu servidor, aqui vai uma super-despojado PHP às coisas do punho:

$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;

Onde call-o-http-post-aqui é o seu mecanismo favorito pós HTTP. ( cURL é uma escolha possível. YMMV. PHP.net tem a colher!)

Uma coisa que tem me um pouco preocupado é o comprimento da carga útil na URL que vai do aplicativo para o servidor (via GET). Eu esqueço se há um problema de comprimento lá acordo com as RFCs. Talvez seja OK, ou específico server-Talvez seja. (Leitores: Assessoria bem-vindo a esta parte)

Também pode haver alguns recusando a fazer deste um pedido síncrono. Você pode querer postá-lo de forma assíncrona e colocar o ol' UIActivityIndicatorView ou algum outro HUD. Caso em questão: Que initWithData: encoding: chamada leva um tempo loooooong para mim. Poucos segundos, que é uma pequena eternidade no iPhone terra (ou em qualquer outro lugar on-line, para que o assunto). Mostrando algum tipo de indicador de progresso indeterminado pode ser aconselhável.

Outras dicas

O código fonte completo, bem como um exemplo hospedado de uma implementação PHP está disponível em: https://github.com/chrismaddern/iOS-Receipt-Validator-PHP

Espero que ajude você!

Para quem está se perguntando como lidar com conexão ou verificação de erros que podem ocorrer quando você estiver usando o modelo de servidor In-App-Compra. validação recebimento garante que a transação está completa e bem sucedida. Você não quer fazer isso a partir do iPhone, porque você não pode realmente confiar telefone do usuário.

  1. Os iniciados usuário uma compra in-app
  2. Quando concluído, o aplicativo pede o servidor para validação
  3. Você validar o recibo com Apple: se é válido, você pode executar qualquer ação relacionada à compra (desbloqueio / entregar conteúdo, cadastre assinatura ...)
  4. O aplicativo remove a transação da fila (finishTransaction)

Se o servidor está em baixo, você não deve concluir a transação, mas exibir uma "mensagem de indisponibilidade" para o usuário.

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

será chamado novamente mais tarde.

Mas se você descobrir que um recibo é inválido, você deve concluir a transação associada. Se não, você pode ter extra-transações que vivem para sempre na fila de transação. Isso significa que cada vez que suas corridas de aplicativos, paymentQueue: updatedTransaction: será chamada uma vez por transação ...

Em minhas aplicações, validação recibo é feito através de um serviço web, retornando um código de erro em caso de recebimento inválido. É por isso que um servidor externo é necessário. Se um usuário de alguma forma consegue ignorar a validação recibo (por simular o serviço web "sucesso" de resposta), ele não será capaz de desbloquear a funcionalidade content / acesso porque o servidor não tem nenhum traço da compra.

Depois de lutar com isso por algum tempo, eu finalmente encontrei uma lista de códigos de status na documentação da Apple, incluindo o temido 21002 (que é "Os dados na propriedade recebimento-dados foi mal formado.") . Enquanto eu vi relatos de outros códigos de status não incluídos nesta lista, eu até agora não vi nenhum além do que a Apple tem documentado. Note-se que estes códigos são válidos apenas para auto-renovar assinaturas, e não outros tipos de in-app-compras (ou assim diz o documento).

O documento em questão pode ser encontrada aqui .

Estou surpreso de não ter encontrado tutorial de Ray Wenderlich aqui - apenas salvou minha vida. Passa por validar recibos sem um servidor (não uma solução recomendada, mas fortemente feito de qualquer maneira).

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

Você deve enviar o recebimento como um arquivo para o seu servidor PHP. Em seu lado PHP você pode usar esse script para validar:

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

Apenas para abrir este novo e adicionar meus 2 centavos em troca de flagelação estas formas para obter informações.

Eu apenas configurar um serviço IAP em meu aplicativo e correu para o mesmo 21002 erro. Achei o 21002 acontece quando quer o cargo para o seu servidor PHP está vazio (assim o pedido HTTP para a App Store está vazia) ou incorrectamente formatado. Para chegar ao nosso trabalho, no lado do iPhone que defina os dados de postagem em um NSString como base64 codificado em seguida, enviá-lo para o nosso servidor como um pedido HTTP.

Então em nosso servidor, nós preso em uma array e JSON ed-lo. Como esta:

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

Você verá que é o mesmo que acima, exceto estamos usando um POST em vez de um GET. A preferência pessoal realmente.

Em seguida, usamos CURL para postá-lo para a caixa de areia e json_decode usado na resposta.

Esta é uma grande biblioteca que fazer o que ninguém precisa sobre este assunto:

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

Ele vai além e valida:

  • iTunes
  • Play Store
  • Amazon App Store

Espero que ajude alguém mais como está me ajudando.

Se você está recebendo respostas nulos ou códigos de erro, por exemplo, 21002, tente adicionar essas linhas. Se você verificou os códigos de erro onda, é um erro de certificado SSL ...

curl_setopt ($curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top