GoogleがIn-app Billing Version 2 APIを殺すそうなので、もう長らく更新していなかったAndroidアプリを更新する羽目になっています。
昔version2の頃にアプリ内課金を実装したときは、正直意味が分からないけどサンプル通りに書いたら動いたというレベルだったので、結構苦手意識があります。
ただ、すごくシンプルになったという話も聞くので、これを機にまとめてみようと思います。
- AIDLファイルの追加
Android SDK ManagerでGoogle Play Billing Libraryをインストールします 。
<android-sdk>/extras/google/play_billing/samples/TrivialDrive/からサンプルプロジェクトをインポートします。
TrivialDrivaサンプルの/srcディレクトリからIInAppBillingService.aidlファイルをコピーし、自分のアプリの/srcディレクトリへ貼り付けます。
/genディレクトリ内にIInAppBillingService.javaが自動的に作成されます。
- AndroidManifestの更新
AndroidManifest.xmlに以下のパーミッションを追加します。
<uses-permission android:name="com.android.vending.BILLING" />
- ServiceConnectionの作成とIInAppBillingServiceへのバインド
ServiceConnectionを実装します。
private IInAppBillingService mIInAppBillingService; private ServiceConnection mServiceConnection= new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { mIInAppBillingService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { mIInAppBillingService = IInAppBillingService.Stub.asInterface(service); } };
IInAppBillingServiceを使用できるようにするため、ActivityのonCreateメソッドでbindServiceメソッドを呼びます。
Intentの引数は、クラス名のIInAppBillingServiceではなく、InAppBillingServiceなのが紛らわしいですね。
Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); bindService(serviceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
終了処理として、Activityが終了時にonDestroyメソッドでunbindServiceメソッドでアンバインドします。
if (mServiceConnection != null) { unbindService(mServiceConnection); }
なお、このあたりで大きくハマったのですが、bindServiceを呼んでからServiceConnectionのonServiceConnectedが呼ばれるまでにはタイムラグがあり、直後にIInAppBillingServiceをいじくろうとするとぬるぽで死にます。
bindService自体はtrueで返ってくるのに、IInAppBillingServiceはnullのまま。
時間を計ってみたところ、50~150ミリ秒後ぐらいでまちまちでしたが、何にしろタイムラグがあります。
直後にスレッド止めたりして待ち合わせをしても、ほぼ同時に返ってくるものの結局ぬるぽ。
まぁ何のためにonServiceConnectedメソッドを実装する必要があるのか考えれば、分かりそうなものでしたが。。
ということで、わざわざコールバックメソッドを実装させられている訳なので、onServiceConnectedからトリガーしてあげればぬるぽにはならない訳です。
- サポート状況の確認
int response = mIInAppBillingService.isBillingSupported(3, getPackageName(), "inapp"); if(response == BILLING_RESPONSE_RESULT_OK) { //OKの場合の処理 }
- 購入状況の確認
RESPONSE_CODEや、INAPP_PURCHASE_ITEM_LISTなど、いくつかの情報を含むBundleが返されるので、必要に応じて取り出し利用します。
Bundle bundle = mIInAppBillingService.getPurchases(3, getPackageName(), "inapp", null); if(bundle.getInt("RESPONSE_CODE") == BILLING_RESPONSE_RESULT_OK) { ArrayList<String> purchases = bundle.getStringArrayList("INAPP_PURCHASE_ITEM_LIST"); for (int i = 0, n = purchases.size(); i < n; i++) { //purchases.get(i)の中身によって処理を変える。 } }
- 購入処理
取得したPendingIntenでstartIntentSenderForResultメソッドを呼び出します。
getBuyIntentメソッドの第4引数はDeveloper Payloadというやつで、空文字でもnullでもレスポンス時には空文字が返ってきます。
本来は任意の文字列を入れて、海賊版対策に使います。
startIntentSenderForResultメソッドの第2引数はコールバックを受けたときにリクエストを識別するための任意のint値です。
Bundle buyIntentBundle = mIInAppBillingService.getBuyIntent(3, getPackageName(), itemId, "inapp", ""); if (buyIntentBundle.getInt("RESPONSE_CODE") == BILLING_RESPONSE_RESULT_OK) { PendingIntent pendingIntent = buyIntentBundle .getParcelable("BUY_INTENT"); startIntentSenderForResult(pendingIntent.getIntentSender(), REQUEST_CODE, new Intent(), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0)); }
なお、サポート状況の確認から購入処理まで、IInAppBillingServiceのメソッドを呼ぶ際には、RemoteExceptionが発生するので、適時catchします。
あとはActivityのonActivityResultへレスポンスが来るので、適時処理するだけです。
次回はstartIntentSenderForResultのレスポンス部分、onActivityResultでの処理についてです。
0 件のコメント:
コメントを投稿