最近やる機会のあった、Androidのアプリ内課金(月額課金)の実装のメモ。
ライブラリの設定
まずは実装に必要なGoogle Play Billing Libraryを追加。
compile 'com.android.billingclient:billing:1.0'
Googleで調べたりすると、IInAppBillingService
をプロジェクトに追加してゴニョゴニョ…ってやり方がよく出てくるが、最近は上記のライブラリを使えば良さそう。
パーミッションをAndroidManifest.xml
に追加する必要もない。
アプリ内購入機能への接続開始・終了
基本的にBillingClient
クラスを利用して処理を書いていく。
startConnection
でクライアントのセットアップ・サービスへの接続を開始し、その引数のBillingClientStateListener
のonBillingServiceDisconnected
とonBillingSetupFinished
でその結果を受け取ることが可能。後者の引数には、整数のレスポンスコード(BillingClient.BillingResponse
)が入っており、その値に応じて処理を書いていくことになる。
class BillingActivity : AppCompatActivity(), PurchasesUpdatedListener {
private lateinit var billingClient: BillingClient
override fun onCreate(savedInstanceState: Bundle?) {
...
billingClient = BillingClient.newBuilder(this).setListener(this).build()
startServiceConnection(null)
}
override fun onDestroy() {
super.onDestroy()
billingClient.endConnection()
}
private fun startServiceConnection(executeOnSuccess: Runnable?) {
if (billingClient.isReady) {
executeOnSuccess?.run()
return
}
billingClient.startConnection(object : BillingClientStateListener {
override fun onBillingServiceDisconnected() {}
override fun onBillingSetupFinished(@BillingClient.BillingResponse responseCode: Int) {
when (responseCode) {
BillingClient.BillingResponse.OK -> executeOnSuccess?.run()
else -> {}
}
}
})
}
// PurchasesUpdatedListener
override fun onPurchasesUpdated(@BillingClient.BillingResponse responseCode: Int, purchases: MutableList<Purchase>?) {
}
}
billingClientのsetListener
の引数はPurchasesUpdatedListener
で、ユーザがアイテムを購入したときなどに呼ばれるonPurchasesUpdated
を提供する。こちらの引数もBillingClient.BillingResponse
。
サービスへの接続を終了する際は、endConnection
を利用。アクティビティのライフサイクルに合わせて、onDestroy
などで実行する。
購入可能なアイテムの取得
BillingClient
を通して、Google Playコンソールで作成したアプリ内で購入できるアイテムを非同期に取得することができる。情報取得に必要なパラメータSkuDetailsParams
に購入アイテムのIDや課金タイプ(今回は月額課金)を指定して、querySkuDetailsAsync
で取得開始。このメソッドの2番目の引数はSkuDetailsResponseListener
となっており、アイテムの情報取得結果が通知されるリスナになっている。
class BillingActivity : AppCompatActivity(), PurchasesUpdatedListener, SkuDetailsResponseListener {
private fun retrieveSubscriptionItems() {
val executeOnConnectedService = Runnable {
val params: SkuDetailsParams.Builder = SkuDetailsParams.newBuilder()
.setSkusList(listOf("itemA", "itemB"))
.setType(BillingClient.SkuType.SUBS)
billingClient.querySkuDetailsAsync(params.build(), this)
}
startServiceConnection(executeOnConnectedService)
}
// SkuDetailsResponseListener
override fun onSkuDetailsResponse(@BillingClient.BillingResponse responseCode: Int, skuDetailsList: MutableList<SkuDetails>?) {
when (responseCode) {
BillingClient.BillingResponse.OK -> {
if (skuDetailsList != null) {
skuDetailsList.forEach { ... }
return
}
}
else -> {}
}
}
}
正常に取得できた際に受け取れるSkuDetails
クラスを通して、各アイテムの価格や説明などを得ることができる。
購入
購入にはbillingClientのlaunchBillingFlow
を利用する。
購入に必要なパラメータはBillingFlowParams
が提供している。アイテム名や購入タイプを指定するほか、ユーザを一意に識別する文字列やアップグレード/ダウングレード時の請求のオプションなどを指定する。
また、既に別のアイテムを購入済で、新しい購入の扱いがダウングレード/アップグレードとなる場合、addOldSku
で購入済のアイテムのIDを指定しておかないといけない。
class BillingActivity : AppCompatActivity(), PurchasesUpdatedListener, SkuDetailsResponseListener {
override fun startBillingFlow() {
val executeOnConnectedService = Runnable {
val billingFlowParamsBuilder = BillingFlowParams.newBuilder()
.setSku("itemA")
.setAccountId("XXXXXXXXXXXXXXX")
.setReplaceSkusProration(true)
.setType(BillingClient.SkuType.SUBS)
.setVrPurchaseFlow(false)
billingClient.launchBillingFlow(this, billingFlowParamsBuilder.build())
}
startServiceConnection(executeOnConnectedService)
}
// PurchasesUpdatedListener
override fun onPurchasesUpdated(@BillingClient.BillingResponse responseCode: Int, purchases: MutableList<Purchase>?) {
when (responseCode) {
BillingClient.BillingResponse.OK -> {
if (purchases != null && purchases.isNotEmpty()) {
....
}
}
BillingClient.BillingResponse.FEATURE_NOT_SUPPORTED -> {}
BillingClient.BillingResponse.ITEM_ALREADY_OWNED -> {}
BillingClient.BillingResponse.USER_CANCELED -> {}
else -> {}
}
}
}
最初に書いたとおり、購入の結果はonPurchasesUpdated
に通知され、レスポンスに応じて処理を分けていく。
購入済のアイテムの取得
購入済のアイテムを取得する。Google Playストアアプリのキャッシュを利用するため、ネットワークを介さずに同期的に取得可能。
val purchasesList: List<Purchase> = billingClient.queryPurchases(BillingClient.SkuType.SUBS).purchasesList
参考
- Android Developers Blog: Google Play Billing Library 1.0 released
- In-app Billing Overview | Android Developers
- Play Billing Library | Android Developers
- Buy and Subscribe: Monetize your app on Google Play
[PR] 仲間探してます
アトラエで一緒にネイティブアプリやWeアプリを書いてくれる仲間を募集中です!
https://www.green-japan.com/company/172