実例でみるiPhoneアプリ内課金(In App Purchase) アプリへの組み込み このエントリをはてなブックマークに登録

2010年10月12日

amachinamachin / ,

はじめに

あまのです。

iTunes Connectへの登録」から一ヶ月が経ってしまいましたが、今回はアプリへの組み込みについて書きたいと思います。
最近、Wall Calendar LiteというGoogle Calendarのスケジュールを壁紙にするアプリにも組み込みましたので前回のブログを見直すこともできました。

App Storeへのアクセスの流れ

アプリ内課金はStore KitというAPIを利用して、App Storeとやり取りを行います。
具体的にGood Choiceの「機能制限を解除」ボタンが押された時のコードを元に説明します。

流れとしては次のようになっています。

  1. 「機能制限を解除」ボタンを用意
  2. アプリ内課金が許可されているかを確認
  3. プロダクトの取得処理を開始
  4. プロダクト情報をApp Storeから取得
  5. プロダクト購入処理を開始
  6. プロダクト購入処理結果の取得
  7. 購入完了

コードを書く前に

プロダクトIDを確認

アプリ内課金を行う前に、前回設定したプロダクトIDを確認します。
Good Choiceではわかりやすいように、{Bundle identifier}.{プロダクト名}みたいな形にしています。具体的には jp.kray.goodchoice.unlock というような感じになります。

Store Kit Frameworkをリンク

Store Kit Frameworkをアプリに組み込みます。


1. 「機能制限を解除」ボタンを用意

押されると、upgradePlusメソッドが呼ばれます。

[upgradeButton addTarget:self action:@selector(upgradePlus) forControlEvents:UIControlEventTouchUpInside];


2. アプリ内課金が許可されているかを確認

次はアプリ内課金が許可されているかを判別するコードになります。
これはiPhoneの「設定」→「一般」→「機能制限」で「App内での購入」がオンになっているかを確認します。

// アプリ内課金が許可されているかを確認
if ([SKPaymentQueue canMakePayments] == NO) {
// ... アラートを表示 ...
return;
}


3. プロダクトの取得処理を開始

App Storeからプロダクト情報の取得を開始します。

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

NSSet *productIds = [NSSet setWithObject:PRODUCT_ID];
skProductRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIds];
skProductRequest.delegate = self;
[skProductRequest start];


4-5. プロダクト情報の取得と購入処理を開始

「プロダクト情報をApp Storeから取得」と「プロダクト購入処理の開始」はSKProductsRequestDelegateの次のメソッド内で行います。

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
if (response == nil) {
NSLog(@"Product Response is nil");
return;
}

// 確認できなかったidentifierをログに記録
for (NSString *identifier in response.invalidProductIdentifiers) {
NSLog(@"invalid product identifier: %@", identifier);
}

for (SKProduct *product in response.products ) {
NSLog(@"valid product identifier: %@", product.productIdentifier);
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
}


6. プロダクト購入処理結果の取得

購入処理の結果はオブザーバのSKPaymentTransactionObserverを利用して受け取ります。
気をつけたい点として、購入処理途中の結果も送られてくるため、何度もSKPaymentTransactionStatePurchasingが送られてきます。

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
BOOL purchasing = YES;
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
// 購入中
case SKPaymentTransactionStatePurchasing: {
NSLog(@"Payment Transaction Purchasing");
break;
}
// 購入成功
case SKPaymentTransactionStatePurchased: {
NSLog(@"Payment Transaction END Purchased: %@", transaction.transactionIdentifier);
purchasing = NO;
[self completeUpgradePlus];
[queue finishTransaction:transaction];
break;
}
// 購入失敗
case SKPaymentTransactionStateFailed: {
NSLog(@"Payment Transaction END Failed: %@ %@", transaction.transactionIdentifier, transaction.error);
purchasing = NO;
// ... アラートを表示 ...
[queue finishTransaction:transaction];
break;
}
// 購入履歴復元
case SKPaymentTransactionStateRestored: {
NSLog(@"Payment Transaction END Restored: %@", transaction.transactionIdentifier);
// 本来ここに到達しない
purchasing = NO;
[queue finishTransaction:transaction];
break;
}
}
}

if (purchasing == NO) {
[(UIView *)[self.view.window viewWithTag:21] removeFromSuperview];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
}
}


7. 購入完了

購入完了後の処理は、もちろんアプリ毎に違いますが流れとして書いておきます。

// 課金が行われた後、呼び出す
- (void)completeUpgradePlus {
// アップグレード済みとする
[[ZConfig instance] setPlus:YES];
[self.tableView reloadData];
}


サンドボックスでのテスト

前回作成した決済用テストユーザを使ってテストします。
画面のように [Environment: Sandbox] というサンドボックスであることがわかるようになっています。
この時に入力するユーザ名は、決済用テストユーザパスワードを使うようにします。

アドオンを入手アラートユーザ名とパスワードを入力

有料版と無料版について

「有料版と無料版が両方あって、無料版にアプリ内課金を組み込む意味はあるの?」という突っ込みが知り合いからありました。

元々、弊社で作っているアプリはアプリ内課金が無かった頃に作ったもので、アプリ内課金は最近組み込んだため、両方存在してしまっています。

例えば、Good Choiceはアプリ内課金込みの無料版と230円の有料版であるPlusが存在します。
Wall Calendarは、115円のアプリと無料版のLiteが存在します。

両方に組み込んで思ったことですが、実際メンテナンスや開発はかなり面倒です。わかりにくさを補うための説明も余分に必要になる感じです。

確かに有料版とアプリ内課金の無料版があれば、販売機会が増えるため、売上は上がるかもしれません。ただメンテナンスコスト、両方存在するわかりにくさを考えると片方のみでいいのではと思いました。

正直、アプリ内課金はデバッグが大変です。
いろいろ共有して開発やデバッグが少しでも楽になればいいですね!

最後に

この後に、今回の一連のソースをそのまま載せておきます。
そのまま組み込みやすいようにしてありますので、参考にしてみてください。

クレイについてもっと知りたい方は…

  1. クレイの3つの強みを見てみる。
  2. WEBシステムのことなら何でもご相談ください。

「いいね!」で応援よろしくお願いします!

このエントリーに対するコメント

  1. 奇麗にまとめられてますね。僕ももっとわかりやすく紹介したいで
    す。もしよろしければ、こちらをご覧になってください。

    https://sites.google.com/site/storekitdemo/

    naokits

    2010年10月29日, 11:23 PM

  2. 細かい説明でわかりやすく重宝させていただいております。

    おかげさまでGoodChoiceにある「設定」タブのことはわかったのですが

    Good Choiceの「セール」タブででてくるコンテンツに対して、どのように機能限定の設定をつけるのでしょうか?

    自分の腕が未熟なせいもあり、セールタブを開いたときに、追加コンテンツ購入済み、未購入の判断をどうするかわからないところであります。

    もしよろしければご教授のほどよろしくお願いいたします。

    ヒデマロ

    2011年02月14日, 8:30 PM

  3. 「セールタブを開いたときに、追加コンテンツ購入済み、未購入の判断」ですが、機能制限を解除したかどうかの情報をアプリが持っていて、その情報を見て判断しています。

    amachin

    2011年02月18日, 10:45 AM

  4. 検索でたどり着きましたが、これからアプリ内課金を組み込もうとしている者にとても判りやすそうで、情報公開多謝です。

    harakaz

    2011年03月01日, 1:18 PM

  5. ありがとうございます。
    新しい定期購読の課金についても調査していますので、また近日中に公開したいと思います。

    amachin

    2011年03月01日, 11:27 PM

  6. 見やすい情報ありがとうございます。
    appleにも問い合わせはだしているのですが、
    一点質問させてください。
    現在、サーバープロダクト版を進めているのですが、
    課金後の未決済確認や洗い替え等は、
    appleではなく、開発者側で用意するという認識なんでしょうか?
    apple公式のドキュメントにも記載がなく、困っています。

    yano

    2011年06月28日, 2:55 PM

  7. 決済のタイプは、Consumable, Non-consumable, Subscriptionsのうちのどれになりますでしょうか?
    また課金後の未決済確認、洗い替えというのはどういうものでしょうか?

    基本的にはサーバプロダクト版は、サーバ側で決済情報を管理する形になるとは思います。

    amachin

    2011年06月29日, 3:50 PM

  8. とても助かりました!
    おかげさまで、無事、実装/テストまでできました。
    [UIDevice currentDevice] networkAvailableのところが動かないようなので今からReachabilityについて調べて変更しようと思います。
    ありがとうございました!

    Junko

    2011年08月03日, 12:31 PM

  9. いえいえー。
    また不明な点がありましたら、ご連絡ください。

    amachin

    2011年08月03日, 8:33 PM

  10. 普段はWebをやってる者です。
    業務でiPhoneアプリを作ることになり、アプリ内課金の情報を探してるときにここに辿りついて、大変助かりました。
    おかげさまで先日無事リリースされました。
    ありがとうございました!

    cordell

    2011年09月28日, 5:14 PM

  11. 良かったです。
    記事を書いた頃よりも、今は変わっているかもしれないので、わかりにくいところがあったら、ご指摘ください。

    amachin

    2011年09月29日, 9:39 AM

  12. ここを見てなんとかIn App Purchse実装できそうです。
    ありがとうございます。

    ところで、iTunes Connectのテストユーザで
    課金テストをしているのですが、一度課金すると、
    そのユーザは課金済み状態となり、再度未課金状態のテスト
    ができません。

    テストユーザの課金状態をクリアする方法をご存知ないでしょうか?

    jiey

    2011年10月10日, 2:27 AM

  13. ご連絡ありがとうございます。
    クリアする方法は無いと思います。
    私の場合は、新しいユーザを作成して試すようにしています。

    amachin

    2011年10月11日, 5:02 PM

  14. やはりそうなんですね。
    ご返信ありがとうございました。

    今、In App Purchse実装で、テストユーザで課金テストを
    しているのですが、なぜか成功時の「購入手続きが完了しました」
    という画面が表示されない現象が発生しています。
    (成功のレスポンスSKPaymentTransactionStatePurchasedは返ってくるので、課金自体は成功しているのですが・・・)

    その調査のために、たくさんテストユーザを消費しているところです(汗)

    jiey

    2011年10月15日, 3:15 PM

  15. 横からすみません。
    自分も今、課金部分の組み込みをしているのですが、itunes Connectに載せるために「購入手続きが完了しました」の画面のスクリーンショットを取りたいのですが、表示されないです。

    これってappleの仕様変更なのですかね。。。

    別の部分のスクリーンショットを載せれば申請通るのだろうか。。。

    tetetoto

    2011年11月01日, 12:30 PM

  16. 私も横からすみません。
    jieyさん、tetetotoさん同様、「購入手続きが完了しました」画面が表示されなくって困っています。
    皆さん、何か解決策見つかりました?

    corydoras

    2011年11月12日, 11:03 AM

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


トラックバック
  1. 新しい定期購読型のアプリ内課金を実装してみた (Auto-renewable Subscriptions) | KRAY Inc2011/04/07, 1:24 PM

    […] 実例でみるiPhoneアプリ内課金(In App Purchase) アプリへの組み込み […]

  2. 実例でみるiPhoneアプリ内課金(In App Purchase) iTunes Connectへの登録 | KRAY Inc2011/04/11, 7:03 PM

    […] 実例でみるiPhoneアプリ内課金(In App Purchase) アプリへの組み込み […]

  3. aboy » iPhoneアプリ内課金(In App Purchase)2011/05/24, 5:36 PM

    […] ・実装方法 http://kray.jp/blog/iphone-in-app-purchase-2/ […]

  4. アプリ内課金方法:参考資料 | WP2011/07/20, 9:30 PM

    […] – 実例でみるiPhoneアプリ内課金(In App Purchase) アプリへの組み込み | KRAY Inc […]

  5. superplastic.jp » Blog Archive » iPhoneでアプリ内課金をするには。2011/11/13, 5:02 PM

    […] 実例でみるiPhoneアプリ内課金(In App Purchase) アプリへの組み込み […]

  6. iphone in app purchaseではまりました | ダイナースカード ファンクラブ2012/05/29, 4:51 AM

    […] 失敗しない iOS In-App Purchase プログラミング – A Day In The Life実例でみるiPhoneアプリ内課金(In App Purchase) アプリへの組み込み | KRAY Inc […]

  7. iPhoneアプリのアプリ内課金を実装するときの参考URLまとめ « TakuLog2012/07/17, 10:23 AM

    […] 実装編 実例でみるiPhoneアプリ内課金(In App Purchase) アプリへの組み込み […]

we use!!Ruby on RailsAmazon Web Services

このページの先頭へ