web-dev-qa-db-ja.com

アプリ内購入の領収書を確認する

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

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

ストアキットプログラミングガイドとクラス参照は、この特定の領域には役に立たないものではありません。実際の例は何も提供していないため、役に立つ article まだ間違っています。

基本的に、領収書の検証作業をしている人がどこにも行かないので、自分のコードを喜んで共有してくれるかどうか疑問に思っています。

ありがとう

40
Andy

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

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

注:あなたはcouldlibcryptoのようなものを使用して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は選択肢の1つです。YMMV。PHP.netにはスクープがあります!)

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

また、これを同期要求にするのが多少困難になる場合があります。非同期に投稿して、ol 'IActivityIndi​​catorViewまたは他のHUDを配置することができます。適切な例:initWithData:encoding:呼び出しには時間がかかります。数秒。これは、iPhoneの土地(または、オンラインのどこでも)での小さな永遠です。何らかの不確定な進行状況インジケータを表示することをお勧めします。

70
Joe D'Andrea

完全なソースコードと、PHP実装のホストされた例は、次の場所で利用可能です: https://github.com/chrismaddern/iOS-Receipt-Validator-PHP

それがあなたを助けることを願っています!

7
Chris Maddern

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

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

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

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

後で再度呼び出されます。

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

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

3
leviathan

ここでレイウェンダリッヒのチュートリアルを見つけられなかったことに驚きました-私の命を救っただけです。サーバーなしでレシートの検証を行います(推奨されるソリューションではありませんが、とにかく頻繁に行われます)。

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

1
capikaw

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

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

1
t-dub

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

1
Eduardo Irias

これをもう一度開いて、情報のためにこれらのフォームを精査する代わりに、私の2セントを追加します。

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

次に、サーバー上でそれをスタックし、配列してjsonしました。このような:

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

GETの代わりにPOSTを使用していることを除いて、上記と同じであることに気づくでしょう。実際に個人的な好み。

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

0
Ginamin

これは、このテーマに関して誰もが必要とすることを行う素晴らしいライブラリです。

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

それはさらに検証します:

  • iTunes
  • プレイストア
  • Amazon App Store

誰かが私を助けてくれるようなものになることを願っています.

0
Lucas