何が変わり、なぜ今なのか
Google は、すべての Android アプリに課金コードを最新に保つことを求めています。2026 年 8 月 31 日までに、 新規アプリと既存アプリのすべてのアップデートは Google Play Billing Library v8 以降を使う必要があります (2026 年 5 月にリリースされた v9 も条件を満たします)。Play Console では、2026 年 11 月 1 日までの一度きりの延長を申請できます。 これは公開のゲートです。インストール済みのアプリはそのまま動きますが、v8 以降にしない限り、アップデートは一切公開できません。
やっかいなのは、これが毎年起きることです。2026 年は v8 が下限、2027 年は v9、と続きます。 バージョンが上がるたびに API が削除され、コードの変更を迫られます。Google 自身の Play Billing コードラボもいまだに v5 のままで、 「非推奨」バナーが付いています。このスピード感がよくわかる例です。
このコードラボでは、長く効く解決策を示します。RevenueCat へ移行すれば、RevenueCat が Billing Library を管理してくれるので、二度とバージョンを追いかけずに済みます。次の作業を進めます。
- v8 と v9 が削除したものを正確に確認します(手作業で BillingClient にパッチを当てる場合でも役立ちます)。
- RevenueCat を追加し、
launchBillingFlowによる購入コードを置き換えます。 - 既存のサブスクライバーを移行し、有料ユーザーがアクセスを失わないようにします。
BillingClient) を直接組み込んでいる Android アプリの開発者です。例はすべて Kotlin です。
移行の 2 つの道
期限をクリアする道は 2 つあります。どちらも有効ですが、このコードラボでは 2 つ目をおすすめします。
| 道 | やること | 翌年 |
|---|---|---|
| 自分で BillingClient を v8 にパッチする | 削除された API(ステップ 3)を自分の課金コードで書き直す | v9、v10 と、また同じことをやる |
| RevenueCat へ移行する | 課金コードを一度だけ置き換える。Billing Library は RevenueCat が持つ | RevenueCat SDK を更新する。BillingClient の書き直しは不要 |
単一の商品しか販売しておらず、ペイウォール、実験、クロスプラットフォーム対応を追加する予定が今後もないなら、 手作業でのパッチでも問題ありません。ただ大半のアプリでは、1 つ目の道にかかる毎年のコストこそが、2 つ目を選ぶ理由になります。
v8 と v9 で壊れたもの
参考までに、素の Billing Library が v8(2025 年 6 月 30 日リリース)で削除したものを挙げます。手作業でパッチを当てるなら、 これが作業リストです。RevenueCat へ移行するなら、逆にこのコードを削除することになります。
| v8 で削除 | 置き換え先 |
|---|---|
querySkuDetailsAsync()、SkuDetails |
queryProductDetailsAsync()、ProductDetails、QueryProductDetailsParams |
queryPurchaseHistoryAsync()、PurchaseHistoryRecord |
queryPurchasesAsync()(アクティブなサブスクリプションと未消費の買い切り購入のみ。無効化された履歴にはサーバーの Voided Purchases API が必要) |
enablePendingPurchases()(引数なし) |
enablePendingPurchases(PendingPurchasesParams) |
ProrationMode |
setSubscriptionReplacementMode() 経由の ReplacementMode |
setSkuDetails() |
setProductDetailsParamsList() |
v9(2026 年 5 月 19 日)の変更は小さいものの、それでもコードに影響します。ブロックされた Play Store のエラーが
ERROR から BILLING_UNAVAILABLE に変わり、外部支払いのフィールドが nullable になり、
ターゲット SDK が 35 に引き上げられました。(onProductDetailsResponse リスナーのシグネチャ変更と、新しい課金サブレスポンスコードは
v8 の時点で入っています。)最小 SDK は v8.1 で API 23 (Android 6.0) に上がりました。
RevenueCat が終わらせる仕組み
RevenueCat Android SDK は、Google Play Billing Library を同梱して管理します。現行の SDK は推移的依存として
Billing Library 8.3.0 を同梱しているので、com.android.billingclient:billing を自分で追加する必要はなく、
BillingClient を呼び出すこともまったくありません。
これが毎年の期限にとって意味するのは次のことです。
- 今: RevenueCat SDK を一度だけ導入します(このコードラボの残りの内容)。
- 翌年、v9 や v10 が必須になったとき: RevenueCat SDK のバージョンを上げるだけです。BillingClient の書き直しも、削除された API 探しもありません。
さらに、本来なら自分で作ることになるものも手に入ります。単一の情報源となる customerInfo.entitlements、
サーバー側のレシート検証、Webhook、そして後から使える Paywalls、Experiments、Customer Center です。
RevenueCat を追加して構成する
アプリモジュールの Gradle ファイルに SDK を追加します(最新バージョンを使ってください)。
// app/build.gradle.kts
dependencies {
implementation("com.revenuecat.purchases:purchases:10.10.0")
// Optional: paywalls + Customer Center (requires minSdk 24)
// implementation("com.revenuecat.purchases:purchases-ui:10.10.0")
}
// Remove your old: implementation("com.android.billingclient:billing:...")
この SDK は minSdk 23 (Android 6.0) が必要です。Application クラスで一度だけ構成します。
// MainApplication.kt
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
Purchases.logLevel = LogLevel.DEBUG
Purchases.configure(
PurchasesConfiguration.Builder(this, "goog_YOUR_PUBLIC_SDK_KEY")
// .purchasesAreCompletedBy(PurchasesAreCompletedBy.REVENUECAT) // default: full migration
.build()
)
}
}
goog_ で始まり、RevenueCat ダッシュボードの
Project Settings > API keys にあります。シークレットキーをアプリに埋め込んではいけません。
デフォルトの PurchasesAreCompletedBy.REVENUECAT は、RevenueCat が購入を完了(承認)することを意味します。
MY_APP に切り替えるのは、ステップ 9 の段階的な道の場合だけにしてください。
課金の概念を対応づける
RevenueCat は、ハードコードした SKU と独自の「プレミアムかどうか」の判定を、小さくて長く使えるモデルに置き換えます。次の要素をダッシュボードで構成します。
| 素の Billing Library | RevenueCat |
|---|---|
SKU / ProductDetails(例: premium_monthly) |
プロダクト(RevenueCat にインポートしたストア商品) |
| (SKU リストをハードコードしていた) | オファリング(提示する内容)の中の パッケージ(月額/年額といった役割) |
独自の isPremium ブール値 |
エンタイトルメント(例: pro)。customerInfo 経由で確認 |
ダッシュボードでは、既存の Google Play 商品をインポートし、エンタイトルメント(たとえば pro)を作成して、各プロダクトをそれに Attach します。
pro アクセスは自動的に復元されます。
購入フローを置き換える
queryProductDetailsAsync / launchBillingFlow / 承認のコードを削除し、
2 つの呼び出しに置き換えます。まず、何を販売するかを取得します。
// Coroutines: fetch the current offering and its packages
val offerings = Purchases.sharedInstance.awaitOfferings()
val packages = offerings.current?.availablePackages.orEmpty()
// Show `packages` in your UI (each pkg.product carries the localized price)
次に、ユーザーが選んだパッケージから購入します。
try {
val result = Purchases.sharedInstance.awaitPurchase(
PurchaseParams.Builder(activity, selectedPackage).build()
)
val customerInfo = result.customerInfo
if (customerInfo.entitlements["pro"]?.isActive == true) {
// Unlock pro. RevenueCat already acknowledged the purchase with Google.
}
} catch (e: PurchasesTransactionException) {
if (!e.userCancelled) {
// Show a real error; userCancelled just means the user backed out.
}
}
コルーチンを使っていない場合は、コールバック形式の同等版 (getOfferingsWith、purchaseWith) もあります。
acknowledgePurchase / consumeAsync の呼び出しは削除してください。
RevenueCat の SDK は初めてですか? Android コードラボと 商品と価格の取得ガイドで、さらに詳しく解説しています。
既存のサブスクライバーを移行する
ここがもっとも重要な部分です。現在の有料ユーザーがアクセスを失ってはいけません。作業は 2 つあり、両方とも行うのが望ましいです。
1. 新しい購入: 自動で追跡する
Google Play アカウントをすでに接続したうえで(Google Play 連携コードラボを参照)、 Google Play のサーバー通知を設定し、サーバー間通知から新しい購入を追跡をオンにします。すると RevenueCat は、 SDK をまだ含まないアプリバージョンからのものも含め、すべての新しい購入を記録します。
2. 既存の購入: 一度だけ同期する
以前の BillingClient コードですでにサブスクライブしたユーザーには、RevenueCat 対応ビルドの初回起動時に
syncPurchases() を一度だけ呼び出します。これは OS のサインインを求めることなく、既存の Google Play 購入を
RevenueCat に送ります。ステップ 6 のプロダクトとエンタイトルメントの紐付けと組み合わせれば、その人の pro
アクセスは自動的に復元されます。
// Run ONCE per subscriber, the first time they open the RevenueCat build.
if (!prefs.getBoolean("rc_migrated", false)) {
Purchases.sharedInstance.syncPurchasesWith(
onError = { /* retry later */ },
onSuccess = { _ -> prefs.edit().putBoolean("rc_migrated", true).apply() }
)
}
syncPurchases を呼ぶと、
レイテンシが増え、顧客を意図せず 1 つに統合(エイリアス化)してしまうことがあります。一度きりのフラグで制御してください
(または、以前のシステムが「サブスクライブ済み」と言うのに RevenueCat がそうでないときだけ呼びます)。
restorePurchases()(OS のサインインを促すことがあります)は、ユーザーがタップする「復元」ボタンの裏側でのみ使ってください。
appUserID) で
RevenueCat を構成するか、同期の前に Purchases.sharedInstance.logIn(userId) を呼び、同期した購入が匿名 ID ではなく
正しい顧客に紐付くようにしてください。
syncPurchases はアクティブなサブスクリプションと
未消費の買い切り購入だけを同期します。期限切れや過去の購入を埋め戻す(正確なグラフや生涯履歴のため)には、
ダッシュボードで Google Historical Import を実行してください。これは 2023 年 7 月まで遡って履歴を取り込みますが、
90 日以上前に期限切れになった購入トークンには既知の欠落があります。
ライセンステスターでテストする
リリース前に、課金されることなく実機で移行を検証します。
- Play Console で Setup > License testing にテスターを追加し、ビルドを Internal または Closed testing トラックに公開します。
- 既存のサブスクリプションを持つテスターとして、新しい RevenueCat ビルドをインストールし、一度きりの
syncPurchasesが実行され、proエンタイトルメントがアクティブになることを確認します。 - 新規のテスターとして、新しいフローで購入を完了し、エンタイトルメントがアンロックされ、トランザクションが RevenueCat に表示されることを確認します。
- RevenueCat ダッシュボードで該当の顧客を確認し、購入とエンタイトルメントが記録されているかを確かめます。
段階的なロールアウトがよい? オブザーバーモードを使う
課金コードを 1 回のリリースで削除する準備ができていない場合は、RevenueCat を
PurchasesAreCompletedBy.MY_APP で構成します。すると、既存のコードが購入を完了(承認)しつつ、
RevenueCat が購入とエンタイトルメントを記録します。以前の購入コードを削除したら、デフォルトの
PurchasesAreCompletedBy.REVENUECAT に切り替えてください。
まとめと得られるもの
Android アプリを素の Billing Library から RevenueCat へ移行しました。
BillingClient(と v8 で削除された API に伴うすべての手直し)をgetOfferings+purchaseに置き換えました。- アクセスの判定を、手作りの SKU ロジックではなく、単一の
proエンタイトルメントとしてモデル化しました。 - 一度きりの
syncPurchasesとプロダクトとエンタイトルメントの紐付けで既存サブスクライバーを移行し、Historical Import で履歴を埋め戻しました。
得られるもの: 2026 年 8 月 31 日の期限をクリアし、v9、v10 とそれ以降が必須になっても、RevenueCat SDK を上げるだけで済みます。 毎年の Billing Library 移行はもう不要です。
次に進む
- Android アプリ内課金とペイウォール: RevenueCat Android 連携の全体像。
- アプリ収益を伸ばすと商品と価格の取得: 課金が片付いた今、何をするか。
- RevenueCat: 既存サブスクリプションの移行とGoogle: Billing Library 8 への移行。