iOS7 のレシートを更新する必要がある場合、適切な方法は SKReceiptRefreshRequest を使用することです。これにより、ユーザーが Apple ID を使用してサインインするための Apple ダイアログが表示されます。また、キャンセルすることもできます。ユーザーがキャンセルを押したかどうかをどのように検出できますか? (もちろん、iOS6 では、これは[[SKPaymentQueue defaultQueue] restoreCompletedTransactions] のキャンセル イベントをキャッチすることで実行できます)。
SKReceiptRefreshRequest オブジェクトには、次の 2 つのメソッドを持つデリゲートがあります。
- (void)requestDidFinish:(SKRequest *)request;
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error;
私のコードでは、ユーザーがキャンセルを押すかどうかに関係なく、requestDidFinish デリゲート メソッドが呼び出されます。
これが重要な理由は、ユーザーが [キャンセル] を押した場合に復元プロセスをキャンセルしたいからです。更新要求の後にレシートが存在しなかった場合、これは比較的簡単な場合があります。ただし、SKReceiptRefreshRequest の前にレシート (一部の購入を含む) がアプリに存在する場合があるため、ユーザーがサインイン ダイアログからキャンセルした場合、レシートはアプリに残ります。
これを行う方法について2つのアイデアがあります。
1) 更新リクエストの前に、バンドルからレシートを削除します。これに関する明らかな問題は、アプリがバンドルからファイルを削除できないことです (たとえば、「インストール後にバンドルからファイルを削除する」を参照)。私は試した。いいえ。
2) リフレッシュ要求の前と後のレシートのバイトをチェックします。それらが異なる場合、これはユーザーがキャンセルを押さなかったことを示しているはずです。違いがない場合、それがキャンセルを押したことを示しているかどうかはわかりません。領収書に購入が含まれている場合、更新された領収書には異なるトランザクション ID (ただし、同じ「元の」トランザクション ID) が必要であるため、バイトが異なると思います。領収書に購入が含まれていない場合、それについてはわかりません。
更新、11/9/15; キャンセルを押したユーザーへの代理応答が変更されたように見えることに気付きました。ここで、didFailWithErrorが呼び出されます。ただし、ユーザーのキャンセルを検出するという問題は残ります。ユーザーが [キャンセル] を押したことと、本物のエラーをどのように区別できますか? 私は iOS8.4 と iOS9.2 (ベータ) でテストしています。この識別性の欠如をバグとして Apple に報告しました (バグ #23476210)。
更新、11/10/15; この問題は、iOS 9.0.2では発生しません。3つのシステムすべてで、同じアプリバイナリを使用して、ほぼ同じ時間間隔でこれを試しました(3つのシステムすべてで20分以内):(A)iOS9.2(13C5050d):問題が発生します(didFailWithErrorが呼び出されます) (B) iOS9.0.2、問題は発生しません (requestDidFinish が呼び出されます)、(C) iOS8.4.1、問題は発生します。3 つのシステム バージョンすべてで、これはシミュレータではなく、実際のハードウェアで実行されます。