アプリ内課金

いまやストア売上のほとんどを占めている”アプリ内課金”。 無料でダウンロードしてもらってから、ゲーム内のアイテム購入、アプリの機能開放などにお金を払ってもらうための仕組みです。

iPhoneはAppStoreを利用する”StoreKit“ライブラリー、そして、AndroidではGooglePlayストアを使う”InAppBilling“APIが用意されています。

双方できることはほとんど同じですが、当然、組み込み方は違います。 同じことがしたいだけのに、iPhoneとAndroidで全く違う実装をしないといけないのは、とても悲しいことです。

HerlockではOSの差、ストアの差を吸収し、ワンソースで運用できるアプリ内課金機能を提供します。

iPhone、Androidのアプリ内課金を行うためのソース

[code] // 1.アイテムを var item = localStorage.getItem( productId ); // 2.購入して billing.purchase( productId, function( purchaseId ){ // 3.付与して item.count++; // 4.保存して localStorage.setItem( productId, item ); // 5.おわり billing.distribute( purchaseId ); }); [/code]

以上です。もちろんiPhone、Androidワンソース。 今回はこの新機能を課金フローに沿って見て行きましょう。

目次

  1. 実装の前に
  2. ストア上の商品を取得する
  3. 商品を購入する
  4. 商品を付与する
  5. 購入フローを終了する
  6. 確実に付与するために

実装の前に

商品を準備する

購入してもらう商品をあらかじめストアに登録します。

iPhone ・・・ iTunes Connect

Anctoid ・・・ Google Play Developer Console Herlockのアプリ内課金機能は”消費型”と呼ばれる、ユーザーがいくつでも購入、消費できるモデルを利用します。

AppStoreは”Consumable”、GooglePlayは”管理対象外の商品”で作成してください。 商品ごとに登録する情報は

  • プロダクトID (サービスID、商品ID等、呼び名にブレがある)
  • 商品名
  • 説明
  • 値段
  • その他設定 (配布地域、教育向けフラグ等。ストアによって異なる)

iPhoneとAndroidで同じ設定にしたい場合がほとんどだと思います。 GooglePlayのほうが融通がきくので、iPhone向けを先に設定することをオススメします。

課金機能のクラス・オブジェクト

  • window.billing   ・・・ アプリ内課金するための関数を提供する
  • Productクラス   ・・・ 商品情報 ストアに登録した情報を持つ
  • PurchaseInfoクラス   ・・・ 購入情報 レシート情報など購入結果の情報を持つ

ストア上の商品を取得する

アプリによっては商品情報を決め打ちで済ませる事もありますが、多数の商品を扱う場合や、期間限定公開など、ストアから商品リストを取得したい場面は多いものです。

[code] billing.requestProducts( プロダクトID配列, コールバック(商品リスト) ); [/code]

コールバックの引数に商品リストが渡されます。 ※商品リストは配列ではなく { プロダクトID: Productインスタンス,,, } の形式

[code] billing.requestProducts( [ "プロダクトID_1", "プロダクトID_2" ], function( products ){ for( var productId in products ) { var product = products[ productId ]; product.productId; // "プロダクトID" product.title; // "商品名" product.price; // 値段 "¥100" 等 product.description; // "説明文言" } } ); [/code]

このコールバック内で商品一覧を作成、ユーザーへ提示することになると思います。 ※product.priceに予め通貨単位が反映されていることに注意してください。 ※通貨単位はエンドユーザーの利用ストアによって変化します。

商品を購入する

指定プロダクトIDに紐づく商品をエンドユーザーのストアアカウントで購入します。

[code] billing.purchase( "プロダクトID" , 成功時コールバック( 購入処理ID ) , 失敗時コールバック( ) ); [/code]

実行後、確認のアラート画面が表示され、購入が成功すれば第2引数、失敗時は第3引数のコールバックが呼ばれます。

[code] billing.purchase( "プロダクトID", function( purchaseId ){ purchaseId; // 1購入処理ユニークなID // TODO 付与 // TODO 終了処理 }); [/code]

成功コールバックが呼ばれた時点で、エンドユーザーに対する”課金”は発生します。 必ずこの中で”付与”処理を行いましょう。

商品を付与する

単純に個数を+1するもの、仮想通貨を何ポイント分。のようなものなど付与する内容もアプリによって様々です。 ここでは ・デバイスで管理 ・サーバーで管理 の簡単なサンプルを書いてみます。

アプリ内でアイテム管理している場合

window.localStorageでアイテムを管理 ・プロダクトID: { count: 個数 } の形式

[code] billing.purchase( productId, function( purchaseId ){ // 付与 var item = JSON.parse( localStorage.getItem( productId ) ); item.count++; localStorage.setItem( productId, JSON.stringify( item ) ); // TODO 終了処理 }); [/code]

サーバーでアイテム管理している場合

[code] var 購入情報 = billing.getPurchaseInfoById( "購入処理ID" ); [/code]

業務レベルでアプリ内課金する場合、サーバーでアイテム管理するか、課金ログを残す事が多いと思います。

[code] billing.purchase( productId, function( purchaseId ){ // 購入情報を取得する var purchaseInfo = billing.getPurchaseInfoById( purchaseId ); // サーバーへ購入情報を送る var request = new XMLHttpRequest(); request.open( "POST", "https://サービス.com/アイテム付与" ); // 購入情報をJSON文字列化して送る request.send( JSON.stringify( purchaseInfo ) ); request.onload = function( event ) { if( this.responseText === "OK!" ) { // TODO 終了処理 } }; }); [/code]

AppStore,GooglePlay共に、購入済み確認のAPIがサーバーから利用できます。 サーバーサイドで PurchaseInfo の”receipt”プロパティをAPIへ送ってください。 詳細は下記参照。 App Store ・・・ verifyReceipt(PDF P.26) Google Play ・・・ Purchase Status API

購入フローを終了する

[code] billing.distribute( "購入処理ID" ); [/code]

付与処理が正常に完了したら、window.billingに付与の完了を伝えます。 後述の保険機能とセットの処理なので、必ず実行してください。

[code] billing.purchase( "プロダクトID", function( purchaseId ){ …..; // 正常に付与できたら // 購入処理のIDを伝えて終了 billing.distribute( purchaseId ); }); [/code]

確実に付与するために

[code] var 購入情報ID配列 = billing.getUndistributedPurchaseIds(); [/code]

万が一、途中で強制終了してしまった場合のために、保険の機能が用意されています。 アプリ起動時の初期化処理内で呼びましょう。 アプリ内でアイテム管理している場合のサンプル

[code] var purchaseIds = billing.getUndistributedPurchaseIds(); for( var i=0, len=purchaseIds.length; i<len; i++ ) { // 購入情報を取得 var info = billing.getPurchaseInfoById( purchaseIds[i] ); // 付与 var item = JSON.parse( localStorage.getItem( info.productId ) ); item.count++; localStorage.setItem( item.productId, JSON.stringify( item ) ); // 終了処理 billing.distribute( info.productId ); } [/code]

おわりに

アプリ内課金モジュールの解説をしてきました。が、書いてる最中に気づいたんですが、この機能未リリースでした。・・ 社内での運用TESTを経てリリース。となるので恐らく2013/12月中には公開できると思います。

すみません。。。 さて、Herlock(β)をお試し頂いている皆様、誠にありがとうございます。 HerlockJSは絶賛機能拡充中です。

現在公開待ち機能

  • アプリ内課金
  • WebView連携
  • モーションセンサー
  • GeoLocation
  • Push通知
  • 広告連携

・・・ は、ドキュメントの整備、サンプル作成などなど付随する作業が間に合わず公開がすこし遅れています。 なるべく早く公開できるように動いておりますので、今しばらくお待ちください。

あわせて読みたい記事