読者です 読者をやめる 読者になる 読者になる

アプリ内課金をする

Android Kotlin

概要

Android でアプリ内課金を行う方法についての要約です。詳しい内容は参考情報のページに書かれているので、全体を大まかに説明します。

確認環境

参考情報

公式の情報。

公式の情報の一部を翻訳。

注意点など。

要約

アプリ内課金をするにあたって、行うこと。

  • Google Play Developer Console (以下、Developer Console) に登録し、販売アカウントを作る
  • アプリに AIDL ファイルを追加する
  • AndroidManifest.xml<uses-permission android:name="com.android.vending.BILLING" /> を追加する
  • Developer Console で APK をアップロードする
  • Developer Console でアプリ内アイテムを追加する
  • Billing API を使って購入状況を取得する処理、購入する処理、購入したアイテムを消費する処理をコーディングする

販売アカウントを作成する際には、正式な住所の登録が求められる。 使いながら調べた結果から考えて、販売アカウントの住所は購入者にのみ提示されると考えて良さそう。 販売アカウントだけでなく Developer Console アカウントでも住所の登録が求められる。 こちらの住所は Google Play Store で公表される。 アプリやアプリ内アイテムを販売する場合には、連絡可能な現在の有効な住所を登録しないとアカウントまたはアプリの販売が停止される場合があるとのこと。 商店で製品を購入する際にパッケージには生産者の住所が記載されているのと同様、アプリにも住所を明記する必要があるということか。

AIDL ファイルは、Sample (Trivial Drive) にある IInAppBillingService.aidl ファイルをコピーする。 コピーする先は Sample と同じ、src/main/aidl/com/android/vending/billing ディレクトリ。 Sample を参照するには、Import an Android code sample を選択し、続けて Trivial Drive を選択する。

AIDL ファイルを APK に含んだ状態で、APK をアップロードするとアプリ内アイテムを追加できるようになる。 (確認してないので、間違えてたら指摘してください ^^;)

Billing API を使った処理フローは In-app Billing API | Android Developers を参照。 購入処理のフローが図示されている。下記は Billing API を使う処理とその前後の処理を含めたフロー。

  1. bindService
    • Intent、android.content.ServiceConnection インターフェイスを実装したオブジェクト、Context.BIND_AUTO_CREATE の 3 つを引数に渡す
    • Intent は Intent("com.android.vending.billing.InAppBillingService.BIND")
    • Intent には setPackage("com.android.vending") が必要 (In-app Billing Vulnerability - Google Help)
    • ServiceConnection インターフェイスの onServiceConnected メソッドは Service と接続された時に呼ばれる。メソッドの実装では、IInAppBillingService.Stub.asInterface(service) として IInAppBillingService オブジェクトを取得して以降のステップで使用する (service: IBinder)
    • ServiceConnection インターフェイスの onServiceDisconnected メソッドは異常終了した時のみ呼ばれる (Bound Services | Android Developers)
  2. isBillingSupported
    • アプリが実行されている環境でアプリ内課金がサポートされていることを確認
  3. getPurchases
    • 購入済みアイテムを取得
    • 1 回の呼び出しで 700 件までしか取得されず、700 件を超える場合には INAPP_CONTINUATION_TOKEN キーで設定された値を使って続きを取得する
  4. getSkuDetails
  5. getBuyIntent
    • 購入処理を依頼するための Intent を取得
    • 第 5 引数の developerPayload に渡した文字列は、購入処理完了後の onActivityResult にそのまま渡される
    • developerPayload は購入要求を識別するために使われる (Security and Design | Android Developers)
    • ベストプラクティスには、消費されないアイテムではユーザーを特定する文字列(メールアドレスは変更されるので使わない)、消費されるアイテムはランダムの文字列を設定すると記載されている
  6. startIntentSenderForResult
    • getBuyIntent で取得した Intent を使用して、Google Play に購入処理を依頼
    • 自アプリがネットワークを介して通信するのではなく、Google Play がサーバーとの通信や購入処理を行う
    • 購入情報のキャッシュは Google Play が行う
  7. onActivityResult
    • 購入処理が完了(購入、もしくはキャンセル)した時に呼ばれる
    • developerPayload の値を検証する (どのような問題に対応するため?)

API をサポートしていない場合に対応したり、セキュリティを高めたり、700 件を超える場合は続きを取得するようにしたりと複雑な処理が増えてくる。 これらを自ら実装する手間を省きたい時には、Sample (Trivial Drive) の util パッケージのソースコードをコピーして使うと良い。 Activity では IabHelper クラスを使用する。 IabHelper クラスのコンストラクタの第 2 引数には、base64EncodedPublicKey (以下、公開鍵) を渡す。 公開鍵には Developer Console の「サービスと API」メニューから辿った先にある「このアプリのライセンスキー」を使う。 ただし、公開鍵はそのままソースコードに書かず変換した文字列を書き、プログラム中で変換する(Security and Design | Android Developers)。 公開鍵は秘密情報ではないが、他の公開鍵に置き換えられることを防ぐために難読化する。

テスト方法

テストのために課金をし続けていては、手数料をとられて大損する。 テスト方法としては 2 種類の方法が用意されている。

  • Developer Console と連携して、販売アイテムを購入する方法 (課金はされない)
  • Developer Console と連携せずに、テスト用アイテムを購入する方法

開発の早期では、Developer Console と連携しない方法でテストする。 テスト用アイテムとして下記の Product ID (SKU) が用意されている (Testing In-app Billing | Android Developers)。これら Product ID をソースコード中で使用して各種の処理をテストする。

  • android.test.purchased : 購入成功の扱いとなる
  • android.test.canceled : 購入キャンセルの扱いとなる
  • android.test.refunded : 払い戻しの扱いとなる
  • android.test.item_unavailable : 購入不可の扱いとなる

テスト用アイテムの Product ID を用いて購入処理のテストを行った後に、Developer Console に販売アイテムを登録してテストをする。 ソースコード中で使用されている Product ID をテスト用アイテムの Product ID から Developer Console で登録した Product ID に変更する。

Developer Console の「設定」メニューから「アカウントの詳細」を開くと「テスト用のアクセス権がある Gmail アカウント」項目がある。 この項目に指定された Gmail アカウントでアイテムの購入を行うと「これはテスト用の注文です。課金は発生しません。」のようにメッセージが表示され、 購入しても課金されない。

未着手のことがら

下記のことがらについては未着手なので、おいおい調べる。

  • アイテムの消費
  • 定期購読
  • 払い戻し