近況
職場が変わり、Javaの開発から離れ、最近はもはやWebサイトの開発の業務さえ なくなってしまいました。さみしい。
そんな中Androidのネイティブアプリの開発案件が。 Javaの開発経験者だからということで振られたものの、アプリ開発の実業務は今回が初になります。とりあえずやってみたのですが課金アイテムの購入を試そうとして嵌ってしまいました。
ドキュメントをちゃんと読めば問題なかった、という話なんですが つまづいたポイントを書き残したいと思います。
課金アイテムの購入はテストが可能なのか
アプリ内課金を実装して試している開発段階で、実際に請求が発生したらどうしようと思ったのですが そこはちゃんと課金をテストできる仕組みがあるみたいですね。
http://developer.android.com/google/play/billing/billing_testing.html
テストのやり方には2つの方法があるようで
- 開発中のアプリをalpha/beta版に登録する
- Static Responsesを使う
前者の方法だとアプリ登録の手間があるので、手軽ではありません。
Static Responsesを利用する方法ではGoogle Play側で用意されている テスト用のプロダクトIDをリクエストします。まず課金の実装を試すなら こちらがおすすめとドキュメントに書いてありました。
アプリ内課金を試す
実装方法の説明はこちら
http://developer.android.com/google/play/billing/billing_integrate.html
ドキュメントに沿って開発していたんですが、所々つまづいてしまい・・・
AIDLの追加
IInAppBillingService.aidlを追加せよとあります。 AIDLファイルというものは今回お初にお目にかかったのですが、 調べてみるとプロセス間通信を実現するためのものらしいですね。
そしてプロジェクトへの追加の仕方が独特
- SDK ManagerでGoogle Play Billing Libraryをダウンロード
- IInAppBillingService.aidlファイルをコピー
- プロジェクト内にパッケージ(com.android.vending.billing)をつくる
- コピーしたファイルをペースト
- ビルドする(IInAppBillingService.javaができる)
依存関係を追記すればOK、というわけにはいきませんでした。
実装する。そして嵌る
ドキュメントに実装例が記載されています。 そちらにしたがって実装、エミュレータで実行してみたものの NullPointerExceptionが発生してしまい、うまくいきません。
IInAppBillingService mService; ServiceConnection mServiceConn = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { mService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { mService = IInAppBillingService.Stub.asInterface(service); } };
どうもonServiceConnectedが呼び出されず、mServiceがnullのまま。 StackOVerflowにも同じ悩みを抱えている方がいるようですが、 回答の内容を試してみたものの結局解決にいたりませんでした。
http://stackoverflow.com/questions/10635512/android-in-app-billing-null-pointer-exception
半日くらい右往左往していたところ、公式ドキュメントをよく読むとこんな記述が!
To test In-app Billing in an application you must install the application on an Android-powered device.
アプリ内課金は実機でテストしないとダメでした・・・。 エミュレータではテストできないんですね。
ドキュメントをよく読んでなかった私が悪いのですが、 「アプリ内課金はエミュレータでテストできません」とか エラーメッセージが出てくれたら嬉しかった・・・。
- USBケーブル経由で実機にアプリを入れる
- 実機には開発者アカウントまたはテストアカウントでログインする
- 実機のGoogle Play Serviceのバージョンを5.0.12以上にする
これで、サンプルアプリがNullPointerExceptionで落ちずに めでたくアイテム購入のダイアログが出てきました。
Unexpected response code 500 が出たので待つ
ひとまず購入処理をひと通り試すことができました。 安心したところでリファクタリングし、そして再度購入処理を試しました。 しかし失敗。
コンソールには
BasicNetwork.performRequest:Unexpected response code 500
と出ています。 500というとInternal Server Errorですね。 Google Play側のサーバが不調なのか、ということで待機。 結局回復せず、続きは翌日に持ち越しました。 そして日をまたいでからまた試してみるも失敗。
ここまでサーバの調子が悪いのはおかしい、ということで調べてみるとこんな記述が。
http://developer.android.com/google/play/billing/api.html#consume
Once an in-app product is purchased, it is considered to be "owned". In-app products in the "owned" state cannot be purchased from Google Play.
一度購入したアイテムは消費処理をしないと、再度購入することができないようです。 そこでconsumePurchaseメソッドを実行してから、 アイテムを再度購入する、という処理にしてみると無事成功!
まとめ
以上、私がAndroidのアプリ内課金を試す際につまづいたポイントでした。