42

私は数日間アプリの購入で遊んでいますが、常に無効なステータスを取り戻しているため、アプリストアでレシートを検証しようとするまではすべて正常に機能します。

レシートデータをPHPサーバーに渡し、そこからアプリストアに転送しています。有効な応答が得られたら、レシートデータをデータベースに追加する予定です。

ストアキットのプログラミングガイドとクラスリファレンスは、実際にはどのような例も示していないため、この特定の領域では役に立たないものではありません。少し役立つ記事を1つ見つけましたが、それでも問題があります。

基本的に、レシート検証が機能している人が、私がどこにも行かないので、コードを共有してくれるのではないかと思っています。

ありがとう

4

6 に答える 6

71

まず、投稿されたコードにいくつかのタイプミスがあります。これを試して。(免責事項:リファクタリングなどは読者の練習問題として残されています!)

- (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は、お気に入りのHTTPPOSTメカニズムです。(cURLは1つの可能な選択肢です。YMMV。PHP.netにはスクープがあります!)

私が少し心配していることの1つは、アプリからサーバーに(GET経由で)行くURLのペイロードの長さです。RFCごとに長さの問題があるかどうかを忘れています。多分それは大丈夫かもしれません、あるいは多分それはサーバー固有です。(読者:この部分についてのアドバイスを歓迎します!)

また、これを同期要求にすることには多少の不満があるかもしれません。非同期で投稿して、古いUIActivityIndi​​catorViewまたはその他のHUDを設定することをお勧めします。適切な例:そのinitWithData:encoding:呼び出しは私にとって非常に時間がかかります。数秒。これはiPhoneの世界(またはオンラインの他の場所)では小さな永遠です。ある種の不確定な進行状況インジケーターを表示することをお勧めします。

于 2009-08-21T22:38:50.370 に答える
3

アプリ内購入サーバーモデルを使用しているときに発生する可能性のある接続エラーまたは検証エラーを処理する方法を知りたい人のために。領収書の検証により、トランザクションが完了して成功することが保証されます。あなたは本当にユーザーの電話を信頼することができないので、あなたはiPhoneからそれをしたくありません。

  1. ユーザーがアプリ内購入を開始します
  2. 完了すると、アプリはサーバーに検証を要求します
  3. 領収書をAppleで検証します。有効な場合は、購入に関連するすべてのアクションを実行できます(コンテンツのロック解除/配信、サブスクリプションの登録...)
  4. アプリはキューからトランザクションを削除します(finishTransaction)

サーバーがダウンしている場合は、トランザクションを終了するのではなく、ユーザーに「使用不可メッセージ」を表示する必要があります。

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

後でまた呼び出されます。

ただし、領収書が無効であることがわかった場合は、関連する取引を完了する必要があります。そうでない場合は、余分なトランザクションがトランザクションキューに永久に存在する可能性があります。つまり、アプリが実行されるたびに、paymentQueue:updatedTransaction:がトランザクションごとに1回呼び出されます...

私のアプリでは、レシートの検証はWebサービスを介して行われ、レシートが無効な場合はエラーコードが返されます。そのため、外部サーバーが必要です。ユーザーが何らかの方法で(Webサービスの「成功」応答を偽造して)レシートの検証をスキップした場合、サーバーに購入の痕跡がないため、コンテンツ/アクセス機能のロックを解除できなくなります。

于 2011-03-10T08:47:32.947 に答える
1

しばらくこれと戦った後、私はついに、恐ろしい21002(「recipient-dataプロパティのデータが不正でした」)を含む、Appleのドキュメントにステータスコードのリストを見つけました。このリストに含まれていない他のステータスコードの報告を見たことがありますが、これまでのところ、Appleが文書化したものを超えるものは見ていません。これらのコードは自動更新サブスクリプションにのみ有効であり、他の種類のアプリ内購入には有効ではないことに注意してください(またはドキュメントに記載されています)。

問題のドキュメントはここにあります。

于 2011-09-13T21:32:28.527 に答える
1

領収書をファイルとして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

于 2016-06-03T09:02:22.007 に答える
0

これをもう一度開いて、情報を得るためにこれらのフォームを検索する見返りに2セントを追加するだけです。

アプリでIAPサービスを設定したところ、同じ21002エラーが発生しました。21002は、PHPサーバーへの投稿が空の場合(つまり、アプリストアへのHTTPリクエストが空の場合)または不適切にフォーマットされた場合に発生することがわかりました。iPhone側で機能させるために、NSStringの投稿データをbase64エンコードとして設定し、HTTPリクエストとしてサーバーに送信しました。

次に、サーバー上で、サーバーを配列してjson-edしました。このような:

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

GETの代わりにPOSTを使用していることを除けば、上記と同じです。本当に個人的な好み。

次に、CURLを使用してサンドボックスに投稿し、応答でjson_decodeを使用しました。

于 2010-08-12T01:55:43.010 に答える
-2

null応答またはエラーコード(21002など)が表示される場合は、これらの行を追加してみてください。カールエラーコードを確認した場合は、SSL証明書エラーです...

curl_setopt ($curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
于 2010-12-30T04:07:54.347 に答える