iOS In App Purchase(Observer)

In App Purchaseの実装を順に追っていきます。今回は, In App Purchaseの内部処理です。
In App Purchase では, 諸処の処理を, SKPaymentTransactionObserver が面倒を見てくれます。
具体的には, 処理の成功, 処理の失敗,
といったところをObserve 観察して知らせてくれるというものです。App Storeなどとのやり取りは,

処理手順

  • 購入ボタンをクリック
  • SKProductsRequestでリクエストを発行
  • Apple側の処理
  • SKPaymentTransactionObserverでAppleの処理を受け取る
  • 購入後の処理など

といった具合です。会計処理などはApple側が全部やってくれるので, あとは前後の処理を書いていくのみです。
SKProductsRequestは長くなるので別の部分でやるとして, 今回は会計後の処理を行います。

SKPaymentTransactionObserverの拡張クラスを作成して独自の処理を入れる

まずここからです。
PurchaseObserver.h

@interface PurchaseObserver : NSObject<SKPaymentTransactionObserver>
@end

PurchaseObserver.m

-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    // In case of restore, invokes multiple times
    for ( SKPaymentTransaction *transaction in transactions )
    {
        switch ( transaction.transactionState )
        {
            case SKPaymentTransactionStatePurchasing:
                // In process
                break;
                
            case SKPaymentTransactionStateFailed:
                // Fail and cancel
                [self failedTransaction:transaction];
                break;
            case SKPaymentTransactionStateRestored:
                // Restore
                [self restoreTransaction:transaction];
                break;
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
        }
    }
}

-(void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions
{
    // Done
}

-(void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
    // All Restore Done
}

- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error 
{
    // Error restore
}

-(void)completeTransaction: (SKPaymentTransaction *)transaction
{
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    // Purchased
}

-(void)failedTransaction: (SKPaymentTransaction *)transaction
{
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    // Failed
    switch ([transaction.error code])
    {
        case SKErrorUnknown:
            // Unknown
            break;
        case SKErrorClientInvalid:
            // Client Invalid
            break;
        case SKErrorPaymentCancelled:
            // Canceled
            break;
        case SKErrorPaymentInvalid:
            // Payment Invalid
            break;
        case SKErrorPaymentNotAllowed:
            // Not allowed
            break;
        default:
            break;
    }
}

-(void)restoreTransaction: (SKPaymentTransaction *)transaction
{
   [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
   //
}

実際に実装すべきは, paymentQueueとpaymentQueueRestoreCompletedTransactionsFinishedの処理です。

Method 説明
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions 処理の経過,もしくは結果がかえってきます
-(void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions 処理が終了したとき,つまりQueueから取り除かれたときの共通処理
-(void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue リストアすべてが終了した場合
– (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error リストアがキャンセルされた場合

購入の状態により処理

-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
ですが, ここに処理の種類に応じて結果がかえってきます。
これは1つの処理を行います。複数の処理を同時に発行している場合それぞれの処理がここに落ちてきます。

処理状態 説明
SKPaymentTransactionStatePurchasing 購入中(経過がかえってきます)
SKPaymentTransactionStateFailed 失敗
SKPaymentTransactionStateRestored リストア成功
SKPaymentTransactionStatePurchased 購入成功

[[SKPaymentQueue defaultQueue] finishTransaction:transaction]

処理の終了後必ず呼びます。
呼ぶと処理がQueueから排除され終了となります。残っていると延々と処理をすることになります。

失敗した理由による場合分け

ここでは-(void)failedTransaction: (SKPaymentTransaction *)transactionで処理をしています。
SKPaymentTransaction には, エラーコードがあるので, 場合分けが可能です。

作成•登録

このクラスをどこで作成するかというと, まあAppDelegateが妥当なところかと思います。
AppDelegate.h

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) PurchaseObserver *pobserver;
@end

AppDelegate.m

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
   self.pobserver = [[PurchaseObserver alloc] init];
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self.pobserver];
}

SKPaymentQueue に, observerを登録します。これでPaymentの処理をobserveしてくれます。

その後の処理

購入後の処理は,いろいろありますよね。データベースの変更とかでしょうか。
コンテンツなどのダウンロードでレシート使いたい場合もあるでしょう。
SKPaymentTransaction にはそのような購入情報がありますので, これを処理していきます。