Androidで課金アプリ作製 定期購読サンプルコード編
Androidで課金アプリ作製 定期購読編
In-app Billing v3を使用したアプリ開発に必要な最低限のソースコードになります。
シリーズ
・Androidで課金アプリ作製 サンプルコード(BILLING V3) 起動編
・Androidで課金アプリ作製 プロセス間通信予習編
・Androidで課金アプリ作製 定期購読サンプルコード編
開発、動作環境
Eclipse Juno Service Release 2
Android 4.1.2 SC-06D
sample code TRIVIAL DRIVE – SAMPLE FOR IN-APP BILLING VERSION 3
In-app Billing Version 3
OS Windows7
予備知識
・Androidで課金アプリ作製 サンプルコード(BILLING V3) 起動編が動かせたらの話になります。
注意事項
今回は定期購読を例にしますが、テストだと思ってたらカード会社に請求が発生してしまって焦りました。
キャンセルしたので請求は来ないのかな?明細の確認をしてないので不明ですが、テストの際は自己責任でお願いします。
セキュリティー面や、正常に購入処理が行われなかった場合の処理が無いのであくまでも流れをざっくり把握出来る程度のサンプルコードです。
プロジェクト新規作成
今回はプロジェクト名をBillingにしました。
パッケージ名はnet.cochma.billing
以前TrivialDriveから必要なファイルプロジェクトに追加します。
インストール先を変更していないなら以下にあります。
・aidlファイルを追加
/Billing/srcに「com.android.vending.billing」パッケージを追加。
サンプルコードのIInAppBillingService.aidlをドラッグ→ファイルをコピー
追加方法「/Billing/src」にカーソルを合わせて右クリック→新規→パッケージ
正常に追加された場合は「Billing/gen」以下にjavaファイルが生成されます。
・utilファイルを利用
今回はサンプルのutilをそのまま利用させて頂きます。Google先生に感謝。
utilを「/Billing/src」ドラッグで追加。
パッケージ名が変わるのでutil以下のファイルの「package」をutilに変更。
・Manifestファイルに以下を追加
MainActivity.java書き換え
全体のソースコードは下の方に書きますが、先ずは実装に必要な処理を個別に抑えたいと思います。
・解説001
String base64EncodedPublicKey = "[playから取得したキー]";
Androidで課金アプリ作製 サンプルコード(BILLING V3) 起動編でキーの取得方法は書きましたが、playの管理画面より取得する必要があります。
・解説002
ヘルパークラスを生成します。サンプルコードのヘルパークラスをそのまま利用してます。便利です。便利でした。再利用性が高いのは良い事ですね。
引数にはキーを渡しています。
mHelper = new IabHelper(this, base64EncodedPublicKey);
・解説003
ヘルパークラスの中身で「ServiceConnection」をnewしているので課金サービスと接続をしているのが分かります。
ついでに「IBinder」を引数に渡してますが正確に理解してません。プロセス間通信に必要なものらしいのですが詳細は後の課題にします。
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
// セットアップが終ったら呼び出される処理 省略
});
・解説004
セットアップ終了後に呼び出される処理の一つですが、購入情報照会してます。
引数にはリスナーが渡されてます 解説005がリスナーの中身になります。
コールバックとリスナーの区別が未だに出来てません。ややこしいです。同じではダメなのかと思ってしまうのは知識不足だからですね。
mHelper.queryInventoryAsync(mGotInventoryListener);
・解説005
リスナーの中身になります。リスナーの中ではアイテム名を渡して購入情報があるかどうか確認してます。引数がアイテム名です。
Purchase subscriptionPurchase = inventory.getPurchase(subscription001);
・解説006
レイアウトに下記を追加し、ボタンが押されたら呼び出される処理になってます。
android:onClick="onSubscriptionClicked"
下記の記述で購入処理を呼び出してます。
mHelper.launchSubscriptionPurchaseFlow(this, subscription001, RC_REQUEST, mPurchaseFinishedListener, payload);
引数の「mPurchaseFinishedListener」は購入処理後に呼ばれるリスナーです。解説007がリスナーの中身になります。
引数の「payload」は購入の識別子に使用するので何か工夫が必要です。まだ考えてませんが。
・解説007
購入処理が終わった後に呼ばれる処理です。
result.isFailure()
購入の成否を判定します。おそらく失敗時はfalse返却される様です。
purchase.getSku().equals(subscription001)
引数にアイテム名を渡して購入商品の確認してます。期待した値が返却されない場合は商品が間違ってるなど疑うべきですね。
・解説008
購入のリクエストを受け取る処理です。これが無いと購入後の処理が行われません。
解説の位置が微妙でしたが、実際は解説006でリクエストを投げた後に呼ばれて、解説007へと処理が進みます。
onActivity自体何処から呼ばれ、何処へ行くのか良く分かってません。何処かで一歩踏み込んで調べたいと思います。
・解説009
サービスとの連結を解除するとありますが、切断する事の重要性が分かってません。
Httpで言うところのコネクションに近い概念でしょうか?やはり知識不足を感じます。
最後の方は解説が雑になってしまいましたがコードの全容となります。
サンプルコード
実際の所、実戦導入するにはセキュリティーの問題やリクエストが正常に行われなかった場合の処理等をクリアーしないといけません。あくまでも流れを把握する為のサンプルコードです。
public class MainActivity extends Activity {
private final String TAG = "Billing sample";
// リクエストコード
static final int RC_REQUEST = 10001;
// アイテム
static final String subscription001 = "subsctiption001";
// 定期購読アイテム購入フラグ
boolean subScriptionFlag = false;
// ヘルパーオブジェクト
IabHelper mHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d(TAG, "ヘルパーオブジェクト生成");
// playより取得したキーを入力 解説001
String base64EncodedPublicKey = "[playから取得したキー]";
// ヘルパーオブジェクト生成 解説002
mHelper = new IabHelper(this, base64EncodedPublicKey);
// セットアップ開始 解説003
Log.d(TAG, "セットアップ開始");
mHelper.startSetup(new IabHelper.OnIabSetupFinishedListener() {
public void onIabSetupFinished(IabResult result) {
Log.d(TAG, "Setup finished.");
if (!result.isSuccess()) {
Log.d(TAG, "セットアップ失敗 結果: " + result);
return;
}
// オブジェクトが生成されていない
if (mHelper == null) return;
Log.d(TAG, "セットアップ成功。 購入情報照会");
// 解説004 購入情報照会
mHelper.queryInventoryAsync(mGotInventoryListener);
}
});
}
// 解説005
// Listener that's called when we finish querying the items and subscriptions we own
IabHelper.QueryInventoryFinishedListener mGotInventoryListener = new IabHelper.QueryInventoryFinishedListener() {
public void onQueryInventoryFinished(IabResult result, Inventory inventory) {
// オブジェクトが生成されていない
if (mHelper == null) return;
// 購入情報照会失敗
if (result.isFailure()) {
Log.d(TAG,"購入情報照会失敗 結果 : " + result);
return;
}
Log.d(TAG, "Query inventory was successful.");
// 購読情報があるかどうか?
Purchase subscriptionPurchase = inventory.getPurchase(subscription001);
// 購読購入が済んでいる場合はフラグを変更
subScriptionFlag = (subscriptionPurchase != null && verifyDeveloperPayload(subscriptionPurchase));
Log.d(TAG, "User is " + (subScriptionFlag ? "購読購入完了" : "購読未購入"));
Log.d(TAG, "購入情報チェック完了");
}
};
// 解説006 定期購読ボタン
public void onSubscriptionClicked(View arg0) {
Log.d(TAG, "定期購入ボタンクリック");
// 任意の識別子を与える事が出来る。購入後の正当性を確かめるために使用する
// TODO 識別子の生成方法
String payload = "subscription_sample0001";
mHelper.launchSubscriptionPurchaseFlow(this, subscription001, RC_REQUEST, mPurchaseFinishedListener, payload);
}
// 解説007 購入処理が完了した後に呼ばれる処理
IabHelper.OnIabPurchaseFinishedListener mPurchaseFinishedListener = new IabHelper.OnIabPurchaseFinishedListener() {
public void onIabPurchaseFinished(IabResult result, Purchase purchase) {
Log.d(TAG, "Purchase finished: " + result + ", purchase: " + purchase);
// オブジェクトが生成されていない場合は終了
if (mHelper == null) return;
// エラー時の処理
if (result.isFailure()) {
Log.d(TAG, "購入に失敗してます。");
return;
}
// 購入商品がitem001の場合
if (purchase.getSku().equals(subscription001)) {
Log.d(TAG, "subscription001の購入が完了しました。");
// 購入した商品に対応する処理
}
}
};
// 解説008 課金リクエストの結果を受け取る
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d(TAG, "onActivityResult(" + requestCode + "," + resultCode + "," + data);
if (mHelper == null) return;
// Pass on the activity result to the helper for handling
if (!mHelper.handleActivityResult(requestCode, resultCode, data)) {
// not handled, so handle it ourselves (here's where you'd
// perform any handling of activity results not related to in-app
// billing...
super.onActivityResult(requestCode, resultCode, data);
}
else {
Log.d(TAG, "onActivityResult handled by IABUtil.");
}
}
// 解説008 サービスをアンバインド(連結解除) 必須
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Destroying helper.");
if (mHelper != null) {
mHelper.dispose();
mHelper = null;
}
}
// 識別子をチェックする
boolean verifyDeveloperPayload(Purchase p) {
String payload = p.getDeveloperPayload();
// TODO 002 どうやって識別子を保存確認するか
return true;
}
}
今までどれだけ表面的な事しか知らないでAndroidの開発をしてたのか、知ってしまう良い機会となってしまいました。お恥ずかしい限りです。
次回
andoridに関して理解を深めたいと思います。
関連記事
-
-
Macで ローカルサーバー構築 Postfix基本編
Macで ローカルサーバー環境を構築するまで Apache起動編 ネットでの情報は必要最低限しか載
-
-
PHP substr エスケープ処理で文字化け
PHP substr 文字化け mb_substrで文字コードを合わせて切り取ればOKって記事は沢
-
-
jQuery 水平スクロール&cssでカスタム可能なスクロールバーなプラグイン
水平スクロール&cssでカスタム可能なスクロールバーなプラグイン jQueryを使ったプラグインは
-
-
Apache 500 Internal Server Error
久しぶりに自宅のローカルサーバーを動かしたら「Server error!」が出てゑっ!? 解決方法
-
-
Macで ローカルサーバー構築 Apache起動編
Macで ローカルサーバー環境を構築するまで Apache起動編 ネットでの情報は必要最低限しか載
-
-
Google Cloud Messaging プロジェクトナンバー API Key取得編 2014/07最新版
Google Cloud Messaging プロジェクトナンバー APK取得編 コンソールの仕様
-
-
Androidで課金アプリ作製 サンプルコード(BILLING V3) 起動編
Androidで課金アプリ作製 サンプルコード起動編 課金アプリの制作の機会が来てしまいました。
-
-
Macで ローカルサーバー構築 Apache設定編
Macで ローカルサーバー環境を構築するまで Apache設定編 ネットでの情報は必要最低限しか載
-
-
Macで ローカルサーバー構築 ローカルネットワーク参加編
Macで ローカルサーバー環境を構築するまで Apache設定編 ネットでの情報は必要最低限しか載
-
-
jQuery 要素の相対位置
jQueryを使って要素の相対位置を調べる Google先生に「jquery offsetLeft

