Maccle

アプリ内課金のリストア(購入済み)処理が原因でリジェクトされた場合の対処法

 2013.02.28
約 7 分
アプリ内課金のリストア(購入済み)処理が原因でリジェクトされた場合の対処法

アプリ内課金(Store Kit)を組み込んでいたObjective-CのアプリをiTunes ConnectからAppleに申請していたんですが、最近は待てど暮らせど “Waiting for review” から “In review” にステータスが変わるまで超長い!
1ヶ月近くかかっただろうか。。

そしてようやく審査が開始されたと思ったら、初めての “Rejected” !!

早速 iTunes Connect にログインして理由を確認してみると、こんな記載が。

We found that while your app offers In-App Purchase(s) that can be restored, it does not include the required “Restore” feature to allow users to restore the previously purchased In-App Purchase(s), as specified in Restoring Transactions section of the In-App Purchase Programming Guide:

“…if your application supports product types that must be restorable, you must include an interface that allows users to restore these purchases. This interface allows a user to add the product to other devices or, if the original device was wiped, to restore the transaction on the original device.”

To restore previously purchased In-App Purchase products, it would be appropriate to provide a “Restore” button and initiate the restore process when the “Restore” button is tapped by the user.

For more information about restoring transactions and verifying store receipt, please refer to the In-App Purchase Programming Guide.

ふむふむ。
つまり、過去にアプリ内課金で購入済みのユーザーに対するリストア(復元)処理を含めなさい、と。

例えば、過去に既にアプリ内課金をしたユーザーが、何らかの理由で一旦アプリを削除し、再び、同一デバイスまたは別のiPadなり新しいiPhoneなりに同じアプリをインストールした場合、ちゃんと購入履歴をアプリの中でチェックして課金後の状態に戻しなさい(restore)よ、と。

リストアの処理を組み込んでなかった私も私ですが、Appleも今までスルーしてきたくせに、なぜ今回はリジェクトしたんだ!というちぐはぐさはとりあえず考えないことにして、再度Store Kitのリストア処理を見直すことに。

確かに、”restoreCompletedTransactions“で購入履歴のチェックや “paymentQueueRestoreCompletedTransactionsFinished” イベントリスナーのデリゲートなど実装していなかった。

該当アプリでは、購入ボタンで最初に alertView を出し、購入済みか否かをユーザーに確認して、「購入済み」が選ばれた場合は “SKPaymentQueue” の “restoreCompletedTransactions” 関数で履歴をチェックするようにしてみました。

とりあえず、以下のような感じで組み直し、再度Appleにバイナリをアップロードして申請中!

リストア部分のみのサンプル

// アプリ内課金用のプロダクトIDで要求
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:YOUR_PRODUCT_ID]];
request.delegate = self;
[request start];


// プロダクトリクエストコールの受け取り
- (void)productsRequest:(SKProductsRequest *)request 
     didReceiveResponse:(SKProductsResponse *)response {

    if (response == nil) return;
    
    // 確認できなかった場合
    for (NSString *identifier in response.invalidProductIdentifiers) {
        NSLog(@"invalid product identifier: %@", identifier);
    }

    // 確認ができた場合
    for (SKProduct *product in response.products ) {
        if ([product.productIdentifier isEqualToString: YOUR_PRODUCT_ID]) {
            // payment はヘッダに記述済みとする(SKPayment *payment;)
            payment = [[SKPayment paymentWithProduct:product] retain];
            
            // 購入履歴チェック
            [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
            break;
        }
    }
}


// 購入履歴が確認できた場合
- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
    BOOL restore = NO;

    for (SKPaymentTransaction *transaction in queue.transactions) {
        // プロダクトIDが一致した場合
        if (transaction.payment.productIdentifier == YOUR_PRODUCT_ID) {
            restore = YES;
            // *** ここに制限解除や広告削除などの課金後の命令を書く ***

           break;
        }
    }

    // 一致するものがなかった場合
    if (restore == NO) {
        // 通常のアプリ内課金の実行など
        [[SKPaymentQueue defaultQueue] addPayment: payment];
    }
}

// リストアに失敗した場合
- (void) paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
    // 失敗した際の処理をここに
    NSLog(@"Payment restore Failed: %@", error);
}

審査結果はまた後日!

2012/7/31 追記
上記の流れでリストア処理がクリアされて、Appleの承認がおりました!
※実際の実装はもっと細かいですよ。。

About The Author

某IT系なんちゃってエンジニアヨーダ
Apple好きだけど盲目マカーは気持ち悪いと思ってる中道だと思い込んでるしがないダメダメエンジニア。

今もってるApple製品↓
Macbook Pro 15 inch, iMac 27 inch (Late 2009), iPhone 6 Plus, iPad (初代! いらない!)
Follow :

Leave A Reply

*

Comment On Facebook