42 votes

Vérifier le reçu pour un achat dans l'application

J'ai joué avec les achats dans l'application pendant quelques jours, tout fonctionne bien jusqu'au moment où j'essaie de valider le reçu avec l'app store, car je reçois constamment un statut invalide.

Je transmets les données du reçu à mon serveur PHP, puis je les fais suivre au magasin d'applications. Une fois que j'ai obtenu une réponse valide, j'ai l'intention d'ajouter les données du reçu à ma base de données.

Le guide de programmation du kit de magasin et les références de classe sont plus qu'inutiles pour ce domaine particulier car ils ne vous donnent pas vraiment d'exemple, mais j'en ai trouvé un utile. article ce qui m'a un peu aidé mais quelque chose ne va toujours pas.

En fait, je me demande si quelqu'un qui a réussi à faire fonctionner la validation des reçus serait prêt à partager son code, car je n'arrive à rien.

Merci

72voto

Joe D'Andrea Points 3588

Tout d'abord, il y a quelques erreurs de frappe dans le code affiché. Essayez ceci. (Disclaimer : Refactoring et. al est laissé comme un exercice pour le lectorat !)

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

Vous pouvez créer ces méthodes internes sur la classe qui gère votre SKPaymentTransactionObserver messages :

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

Remarque : Vous pourrait utiliser quelque chose comme libcrypto pour gérer l'encodage base64, mais il faut alors tenir compte des restrictions à l'exportation et des étapes supplémentaires au moment de l'approbation de l'application. Mais je m'égare...

Ensuite, quel que soit l'endroit où vous avez l'intention de lancer l'enregistrement de la transaction sur votre serveur distant, appelez vérifier le reçu : avec votre transaction et assurez-vous qu'elle revienne positive.

Pendant ce temps, sur votre serveur, voici du PHP simplifié pour gérer les choses :

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

appelez-votre-poste-http-ici est votre mécanisme d'affichage HTTP préféré. ( cURL est un choix possible. YMMV. PHP.net a le scoop !)

Une chose qui m'inquiète un peu est la longueur de la charge utile dans l'URL allant de l'application au serveur (via GET). Je ne sais plus s'il y a un problème de longueur dans les RFC. Peut-être que c'est correct, ou peut-être que c'est spécifique au serveur. (Lecteurs : vos conseils sont les bienvenus sur ce point !)

Il se peut également qu'il y ait des réticences à faire de cette demande une demande synchrone. Vous voudrez peut-être la poster de manière asynchrone et mettre en place le bon vieil UIActivityIndicatorView ou un autre HUD. Un exemple concret : Ce initWithData:encodage : L'appel prend un loooooong temps pour moi. Quelques secondes, ce qui est une petite éternité au pays de l'iPhone (ou partout ailleurs en ligne, d'ailleurs). L'affichage d'une sorte d'indicateur de progression indéterminé pourrait être conseillé.

0 votes

Merci pour ce que j'ai finalement réussi à faire, je pense que mon problème principal était dans mon code php. Merci encore, Andy

1 votes

Bonjour, en utilisant le script que vous avez fourni ici, je reçois la réponse suivante du serveur : 21002... pouvez-vous me dire ce que cela signifie ? Je vois un autre gars sur ce post qui mentionne un problème similaire. merci pour votre temps.

0 votes

Hmm je ne peux pas dire que j'ai déjà vu cette réponse :( La seule chose que je voudrais vérifier est que vous faites un HTTP poste et non un HTTP obtenir . C'est-à-dire que la charge utile est placée dans les données du message, et non dans la chaîne de requête.

10voto

S.P. Points 3251

Ce site lien avoir tout le code pour écrire php script pour vérifier le reçu .

http://www.phpriot.com/articles/verifying-app-store-receipts-php-curl

7voto

Chris Maddern Points 484

Le code source complet, ainsi qu'un exemple hébergé d'une implémentation PHP sont disponibles à l'adresse suivante : http://www.chrismaddern.com/validate-app-store-iap-receipt-codes-online-tool/

J'espère que cela vous aidera !

4voto

leviathan Points 5207

Pour tous ceux qui se demandent comment gérer les erreurs de connexion ou de vérification qui peuvent survenir lorsque vous utilisez le modèle de serveur In-App-Purchase. La validation du reçu garantit que la transaction est complète et réussie. Vous ne voulez pas faire cela à partir de l'iPhone car vous ne pouvez pas vraiment faire confiance au téléphone de l'utilisateur.

  1. L'utilisateur effectue un achat in-app
  2. Une fois terminé, l'application demande la validation de votre serveur.
  3. Vous validez le reçu auprès d'Apple : s'il est valide, vous pouvez effectuer toute action liée à l'achat (déverrouiller/livrer le contenu, enregistrer l'abonnement...).
  4. L'application supprime la transaction de la file d'attente (finishTransaction).

Si le serveur est en panne, vous ne devez pas terminer la transaction, mais afficher un "message d'indisponibilité" à l'utilisateur.

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

sera à nouveau appelé plus tard.

Mais si vous découvrez qu'un reçu n'est pas valide, vous devez terminer la transaction associée. Sinon, vous risquez d'avoir des transactions supplémentaires vivant éternellement dans la file d'attente des transactions. Cela signifie qu'à chaque exécution de votre application, paymentQueue:updatedTransaction : sera appelé une fois par transaction...

Dans mes applications, la validation des reçus est effectuée par un service web, qui renvoie un code d'erreur en cas de reçu non valide. C'est pourquoi un serveur externe est nécessaire. Si un utilisateur parvient d'une manière ou d'une autre à contourner la validation du reçu (en simulant la réponse "succès" du service web), il ne pourra pas déverrouiller le contenu / accéder aux fonctionnalités car le serveur n'a aucune trace de l'achat.

1voto

t-dub Points 338

Après m'être battu avec cela pendant un certain temps, j'ai finalement trouvé une liste de codes d'état dans la documentation d'Apple, y compris le redoutable 21002 (qui est "Les données de la propriété receipt-data sont mal formées"). Bien que j'aie vu des rapports sur d'autres codes d'état non inclus dans cette liste, je n'en ai pas vu d'autres que ceux documentés par Apple. Notez que ces codes ne sont valables que pour les abonnements à renouvellement automatique, et non pour les autres types d'achats in-app (c'est du moins ce que dit le document).

Le document en question peut être trouvé aquí .

1 votes

Page non trouvée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X