アプリ内課金（自動更新購読型）のサンプル実装の流れ


今回は[CafeSnap](https://itunes.apple.com/jp/app/cafesnap/id910848942)内でテストの課金コンテンツを作成してみます。
## 大まかな流れ
1. テストユーザーの作成
2. 商品の作成
3. テストコードを実装
4. 実機でsandboxユーザーを使って購入処理確認

## 1. テストユーザーの作成
ユーザーと役割を選択
![スクリーンショット 2015-03-11 10.22.41 1.png](https://qiita-image-store.s3.amazonaws.com/0/10532/ed058ec9-f795-b073-3b2f-c9f042688a83.png "スクリーンショット 2015-03-11 10.22.41 1.png")

下記画面でユーザーを追加
![スクリーンショット 2015-03-11 10.23.25.png](https://qiita-image-store.s3.amazonaws.com/0/10532/2350a957-ba50-53cc-22d0-729494dfa845.png "スクリーンショット 2015-03-11 10.23.25.png")

## 2. 商品の作成
課金を実装したいアプリの「App内課金」を選択
![スクリーンショット 2015-03-11 13.00.33.png](https://qiita-image-store.s3.amazonaws.com/0/10532/293d1224-3157-515c-f7b9-0955332a7a4f.png "スクリーンショット 2015-03-11 13.00.33.png")

いくつか種類があるので適切なものを選択。今回は「自動更新購読」を選択。
![スクリーンショット 2015-03-11 13.03.25.png](https://qiita-image-store.s3.amazonaws.com/0/10532/515bbded-e278-61fb-91e2-28273e65516f.png "スクリーンショット 2015-03-11 13.03.25.png")


## 3. テストコードを実装
適当なViewControllerを1つ用意し、StoreKitのdelegateとobserverのインターフェースを実装

```objectivec:testViewController.h
#import <StoreKit/StoreKit.h>
...
@interface TestViewController : UIViewController<SKProductsRequestDelegate, SKPaymentTransactionObserver>
```
下記はViewControllerの必要なメソッドのみ抜粋しています

```objectivec:testViewController.m
// プロダクトのID指定
- (void)viewDidLoad
{
	NSSet *productIds = [NSSet setWithObjects:@"2.で作成した商品のProductIDを指定", nil];
	SKProductsRequest *productRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIds];
	productRequest.delegate = self;
	
	// 指定したプロダクトでリクエスト
	[productRequest start];
}

#pragma mark - SKProductsRequestDelegate
// 初回のリクエストのdelegateメソッド
// ここでプロダクトIDが正しいかなどがわかります
- (void)productsRequest:(SKProductsRequest *)request
     didReceiveResponse:(SKProductsResponse *)response
{
    for (NSString *invalidProductIdentifier in response.invalidProductIdentifiers) {
        NSLog(@"不正なプロダクトID: %@", invalidProductIdentifier);
    }
    
    SKPayment *payment = [SKPayment paymentWithProduct:[response.products objectAtIndex:0]];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
	// observerの指定
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}

#pragma mark - SKPaymentTransactionObserver
// 購入処理のステータスが変わる毎に呼ばれるObserverメソッドです
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStateFailed:
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                NSLog(@"%@", @"失敗");
                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"%@", @"購入中");
                break;
            case SKPaymentTransactionStateRestored:
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                NSLog(@"%@", @"リストア");
                break;
            case SKPaymentTransactionStatePurchased: {
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                NSLog(@"%@", @"成功");
                
                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"成功" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
                [alert show];

				 // レシートを取得して、この後検証を行います。
				 // 自前で用意したサーバーに送信して検証を行うことを想定しています
                NSURL *receiptURL = [NSBundle mainBundle].appStoreReceiptURL;
                NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
                NSString *encodedReceipt = [receipt base64EncodedStringWithOptions:0];
                NSLog(@"%@", encodedReceipt);

                break;
            }
            default:
                break;
        }
    }
}

```
## 4. 実機でsandboxユーザーを使って購入処理確認
1. まず自分のAppleアカウントをログアウト
2. アプリを実機に転送
3. アプリを起動して、テストした画面を開く
4. 1.で作成したテストアカウントを入力
5. 成功のalertが出ればOK

## ProductIDがInvalidになる場合
下記のチェックリストを確認。特に銀行口座の登録などは先に済ましておく必要があります。
また、開発環境によってBundleIDを分けている場合は、ストアのものと同様のIDでテストする必要があります。

```
Have you enabled In-App Purchases for your App ID?
Have you checked Cleared for Sale for your product?
Have you submitted (and optionally rejected) your application binary?
Does your project’s .plist Bundle ID match your App ID?
Have you generated and installed a new provisioning profile for the new App ID?
Have you configured your project to code sign using this new provisioning profile?
Are you building for iPhone OS 3.0 or above?
Are you using the full product ID when when making an SKProductRequest?
Have you waited several hours since adding your product to iTunes Connect?
Are your bank details active on iTunes Connect? (via Mark)
Have you tried deleting the app from your device and reinstalling?
Is your device jailbroken? If so, you need to revert the jailbreak for IAP to work. (via oh my god, Roman, and xfze)
```

## 5. まとめ
今回はテスト実装のため、ViewController内だけで済んでいますが、実際にはサーバー側にレシートを投げて検証をしたり、課金状態をサーバーサイドで保持していたりと、色々と複雑になってきます。  

定期購読型は、機能に対して月額課金するとリジェクトされる可能性が大きいらしく、雑誌のような更新コンテンツを合わせて用意する必要がありそうです。  

随時追記していきます！！

## 参考リンク
#### テストケース
- 参考になるサイト 
http://tech-gym.com/2012/09/ios/871.html

- 実装の参考になるコード 
https://github.com/ykjchen/JC-Autorenewable-Subscription-Manager-iOS

- アプリ内課金公式ドキュメント 
https://developer.apple.com/jp/documentation/StoreKitGuide.pdf

- レシートに関する公式ドキュメント 
https://developer.apple.com/jp/documentation/ValidateAppStoreReceipt.pdf

## こだわりカフェが探せるCafeSnap
![icon.jpg](https://qiita-image-store.s3.amazonaws.com/0/10532/6295add5-0ba8-2644-f610-9dea2189eb22.jpeg "icon.jpg")

- iOS  
https://itunes.apple.com/jp/app/cafesnap/id910848942
- Andorid  
https://play.google.com/store/apps/details?id=jp.co.allabout.cafesnap