mixiアプリ » 技術仕様(Graph API方式) » 課金API(mixiポイント決済)
課金API(mixiポイント決済)
android向け課金APIを利用することにより、mixiポイントを使ったアイテム課金をmixiアプリandroid版に組み込むことができます。ここでは、mixiアプリにてandroid向け課金APIをどのように利用して組み込むかを説明いたします。
制限事項
ここで説明するandroid向け課金APIの利用は、mixiより許可されたSAPが開発したmixiアプリのみで利用することができます。その際、SAPは開発するmixiアプリごとに許可を得なければなりません。
利用手順
android向け課金APIは、mixi Platform独自の決済確認フローを実装したAPIです。決済内容を保護するために、mixiアプリから規定のSDKインターフェイスを呼び出すだけ でなく、いくつかバックエンド側(SAP側の外部サーバ上)で行わなければならない処理があります。
事前準備
android向け課金APIでは、通信内容の妥当性検証を行うために、署名の生成や検証を行うことになります。使われる署名は、HMAC-SHA1にて 生成された文字列となります。この際に使用されるキーは、mixiアプリの設定画面(edit_appli.pl)にて表示されるConsumer Secretです。予めこのConsumer Secret文字列をその画面より入手しておきます。
基本的な処理フロー
mixiアプリ内でandroid向け課金APIを利用する際の代表的な処理フローを以下に示します。
- mixiアプリからバックエンドサーバに決済情報の作成を依頼する
- バックエンドサーバにて決済情報を作成し、mixiアプリに返却する
- 決済情報を元に、決済のためのAPIを呼び出す
- mixiサーバからバックエンドサーバに、ポイントコードが送信される
- バックエンドサーバはポイントコードを保持し、mixiサーバに結果を返却する
- 決済確認ポップアップ画面が表示される
- ユーザが確認を行い、購入を確定する
- mixiサーバからバックエンドサーバに、決済処理ステータスが送信される
- バックエンドサーバは決済情報を確認後、mixiサーバに結果を返却する
- 決済完了ポップアップ画面が表示され、ユーザがそれを消去する
- 指定したコールバック関数が呼び出され、結果が渡される
1.アイテム情報のリクエスト
ユーザが何らかのアイテムの購入をmixiアプリ内で希望した際に、最初にmixiアプリからバックエンドサーバに対して、決済情報の作成を依頼します。この時点で、購入対象のアイテムIDが決定します。
以下に、サンプルコードを記載いたします。
HttpClient client= new DefaultHttpClient(); HttpGet httpGet = new HttpGet("http://sap_service/get_item.pl?item_id=123"); HttpResponse response = client.execute(); String responseBody = EntityUtils.toString(response.getEntity(), HTTP.UTF_8); JSONObject itemData = new JSONObject(responseBody); String itemName= itemData.getString("itemName"); String itemId= itemData.getString("itemId"); int itemPrice= itemData.getInt("itemPrice"); boolean isTest= itemData.getBoolean("isTest"); String inventory_code = itemData.getString("inventory_code"); String signature= itemData.getString("signature");
2.アイテム情報の作成
アイテム情報の作成要求を受け取ったバックエンドサーバでは、アイテムIDを元に必要な情報を準備し、それらを元に署名を作成します。これらを結果としてmixiアプリに返却します。
アイテム情報として必要な項目を以下に示します。
項目名 | 説明 |
---|---|
callback_url | mixiサーバから呼び出されるバックエンドサーバのURL |
inventory_code | バックエンドサーバー側でこの決済を特定するためのユニークな任意の文字列 |
is_test | 決済処理のテストの場合は”true”, 実際の決済の場合は”false” |
item_id | アイテムID |
item_price | アイテムのポイント数 |
まず、これらの項目を「&」で連結して、1つの文字列を作成します。その際に、項目名はアルファベット順とします。また、全ての項目値はURIエスケープを行っておきます。
callback_url=http%3A%2F%2Fsap.server.host%2Fcreate_order&inventory_code=123&is_test=true&item_id=123&item_price=500
この文字列に対して、さらに以下の加工を行います。その結果は、上記のパラメータに対する署名となります。
- 上記文字列全体をURIエスケープする – (1)
- 予め入手したConsumer Secretの末尾に”&”を付与する – (2)
- (2)をキーとしてHMAC-SHA1アルゴリズムを使用し、(1)のダイジェスト値を得る – (3)
- (3)をBASE64エンコードする
上記のパラメータ値および生成した署名を、mixiアプリに結果として返却します。
※ URIエスケープは、こちら(http://oauth.net/core/1.0a#encoding_parameters)に則って行ってください。
3.決済APIの呼び出し
バックエンドサーバから得られたアイテム情報に基づいて、決済のためのAPIを呼び出します。このAPIとして、SDKのMixiContainer#requestPaymentメソッドを利用します。
PaymentParameter param = new PaymentParameter(); param.callbackUrl = "http://sap_service/callback"; param.inventoryCode = "order123"; param.itemId = "123"; param.itemName = "エクスカリバー"; param.itemPrice = 250; param.isTest = true; param.signature ="TmihyproUc02HOh17W0uz++WdYM="; container.requestPayment(this, param, PAYMENT_REQUEST_CODE,new CallbackListener(){});
まず、決済オブジェクト(PaymentParameter)を生成します。その際に必要となる項目は、以下となります。
フィールド変数名 | 説明 |
---|---|
itemPrice | アイテムのポイント数 |
itemName | アイテム名 |
signature | 決済情報の署名文字列 |
itemId | アイテムID |
isTest | 決済処理のテストの場合は”true”, 実際の決済の場合は”false” |
inventoryCode | バックエンドサーバー側でこの決済を特定するためのユニークな任意の文字列 |
callbackUrl | mixiサーバから呼び出されるバックエンドサーバのURL |
実際の決済処理は、MixiContainer#requestPaymentメソッドによって呼び出します。この関数は、以下の引数を受け付けます。
- 呼び出し元Activityのオブジェクト
- PaymentParameterオブジェクト
- コールバッククラスを呼び出すためのrequestCode
- コールバッククラス
MixiContainer#requestPaymentメソッドを呼び出すと、mixiサーバに決済開始要求がmixiアプリから送信されます。
残ポイントが足りなかった場合
決済情報に含まれるポイント数について、対象ユーザが必要なポイント数を持っていなかった場合は、ユーザに残高不足を表すポップアップ画面が表示されます。ユーザがポイントチャージを行い、さらにポップアップ画面から続行を選択することで、再度決済処理が行われます。
4.ポイントコードの送信
mixiアプリからMixiContainer#requestPaymentメソッドが呼び出された後、mixiサーバは PaymentParameter#callbackUrlにて指定されたバックエンドサーバのURLにポイントコードを送信します。その際に送られるパ ラメータは以下となります。
パラメータ | 説明 |
---|---|
opensocial_app_id | mixiアプリのID |
opensocial_owner_id | mixiアプリの利用者のハッシュ化されたユーザID |
inventory_code | バックエンドサーバにて採番されたユニークな任意の文字列 |
point_code | この決済を特定するためのポイントコード |
item_id | アイテムのID |
item_price | アイテムのポイント数 |
item_name | アイテムの名前 |
signature | バックエンドサーバにて生成された署名文字列 |
is_test | 決済処理のテストの場合は”true”, 実際の決済の場合は”false” |
このリクエストは、2-legged OAuthによる署名が施されています。署名は、Authenticationヘッダに記載されています。不正な購入を防ぐために、必ずこの署名の検証を 行ってください。検証方法は、mixiアプリモバイルでの仕様と同じです。ただし、検証時のベース文字列として、上記にあげたパラメータに関しても含める ようにしてください。
5.結果の返却
署名の検証後、ポイントコードなど決済内容をバックエンドサーバ側で保持します。その後、成功のレスポンスを返却します。
Status: 200 Content-Type: text/plain OK
このレスポンスは、10秒以内に行う必要があります。10秒以内にレスポンスがなかった場合、決済処理は行われません。
6-7.ユーザによる決済確認
mixiサーバが結果を受信後、ユーザに決済確認のためのポップアップ画面が表示されます。そこでユーザは、決済するかどうかの判断を行います。ユーザが決済を要求することで、mixiサーバ内で決済処理が実行されます。
8.決済処理ステータスの送信
mixiサーバ内で決済処理が行われた後に、再度バックエンドサーバに決済確定のためのリクエストが送信されます。リクエストは、 requestPayment()関数の呼び出し時に渡されたpaymentHandlerUrlで指定したURLとなります。リクエストに含まれるパラ メータは、以下となります。
パラメータ名 | 説明 |
---|---|
opensocial_app_id | mixiアプリのID |
opensocial_owner_id | mixiアプリの利用者のユーザID |
point_code | この決済を特定するためのポイントコード |
status | ステータス 10=購入成功 |
updated | 購入確定日時(UTC) |
statusの値 | 説明 |
---|---|
10 | 購入成功 |
20 | 購入失敗、その他エラー |
このリクエストは、2-legged OAuthによる署名が施されています。署名は、Authenticationヘッダに記載されています。不正な購入を防ぐために、必ずこの署名の検証を行ってください。検証方法は、mixiアプリモバイルでの仕様と同じです。ただし、検証時のベース文字列として、上記にあげたパラメータに関しても含めるようにしてください。
9.結果の返却
署名の検証後、リクエストに含まれる各パラメータに基づいて、バックエンドサーバ側にて決済内容の確認とアイテム購入処理などを行います。その後、成功のレスポンスを返却します。
Status: 200 Content-Type: text/plain OK
このレスポンスは、10秒以内に行う必要があります。10秒以内にレスポンスがなかった場合、決済確定の処理は行われません。
10.ユーザへの決済完了表示
バックエンドサーバから結果を受け取ったmixiサーバは、ユーザに決済完了を示すポップアップ画面を表示します。ユーザは、その画面を閉じます。
11.コールバック関数の呼び出し
Activity#onActivityResult内でMixiContainer#paymentCallbackを呼び出すようにしてください。 決済が成功している場合には、CallbackListener#onCompleteが実行されます。 決済がユーザーによってキャンセルされた場合はCallbackListener#onCancelが実行されます。 決済に何らかのエラーが発生した場合はCallbackListener#onErrorまたはCallbackListener#onFatalが実行されます。 onError,onFatalが実行された場合は、何らかの理由で決済が完了しなかったことを示しています。その場合は、 ErrorInfo#getErrorCode,ErrorInfo.getMessageによりエラーコードなどを取得し、適切なエラー処理を行ってください。
エラー内容の確認方法 CallbackListener内 public void onError(ErrorInfo e){ int errCode = e.getErrorCode(); if(errCode==401){ String message = e.getMessage(); // 権限エラーの処理 } ・ ・ ・ }
上記はサンプルなのでエラーの内容に応じて正しく処理を実装してください。