◉ANTIGRAVITY LABEN
記事一覧/アプリ開発
▣ アプリ開発/2026-05-17上級

課金状態の「正」はどこにある? — Antigravityで設計するad-free Source of Truthパターン

個人開発の壁紙アプリで実際に踏んだ課金状態バグから導いた設計パターン。BillingManager・AdFreeManager・ModalGateの3層設計をAntigravityで実装する実践ガイド。

android29billing3admob16architecture13indie-dev6kotlin6

✦ プレミアム記事

「広告を消す購入をしたのに、まだ表示される」

2026年4月、個人開発で長く運営してきた壁紙アプリ(Android版)のユーザーレビューにこの報告が届きました。購入フロー自体は正常で、Google Play Billing の取引履歴にも記録があります。それでも一部の端末で広告が消えない現象が再現していたのです。

コードを追っていくと、問題の根本が見えてきました。課金状態を判定する条件式が、アプリの5か所に散在していました。それぞれが独立したタイミングで更新され、再起動直後やセッション切り替え時に一時的な矛盾が生じていました。これが原因でした。

運営を長く続けるなかで少しずつ積み上がってきた技術的負債の、ひとつの結晶でした。

この問題を Antigravity と一緒に解決していく中で、「Source of Truth(唯一の真実源)」という設計原則と、それを実現するための3つのクラス——AdFreeManager、BillingManager、ModalGate——の組み合わせにたどり着きました。設計の思考過程と実装の詳細を、以下で共有します。

なぜ「課金状態」は散らばるのか

個人でアプリを長く運営していると、課金状態の判定があちこちに生えていきます。最初はシンプルです。SharedPreferences に is_ad_free フラグを置いて Activity から読むだけです。ところが機能を追加するたびに状況が複雑になっていきます。

リワード広告を導入したとき、「広告を見た人は一定時間だけ ad-free にする」という仕様が加わります。このリワード状態はメモリ上にしか存在しません。次に、購入復元機能を追加したとき、別の判定パスが生まれます。Fragment が増えるたびに、それぞれが微妙に異なる判定ロジックを持つようになります。

こうして気づかないうちに、課金状態は「分散した真実」の集合体になっていきます。それぞれが「正しいはず」なのに、タイミングの違いで矛盾が生まれます。

Antigravity にこの状況を共有したとき、最初の返答はコードの生成ではなく、設計の問いかけでした。「課金状態について、アプリ全体で信頼できる唯一の場所を決めましょう。それが Source of Truth です。どの情報が一番正確だと思いますか?」

この問いかけが、設計の出発点になりました。

Source of Truth という考え方

ソフトウェア設計で「Source of Truth(唯一の真実源)」とは、あるデータについて「これが正しい値だ」と信頼できる唯一の場所を設けるという設計原則です。複数の場所が同じデータを保持し、それぞれが独立して更新される構造は、必然的に矛盾を生みます。

課金状態の場合、Source of Truth の候補は以下の3つが考えられます。

まず、Google Play Billing API の返り値。Google のサーバーに問い合わせた結果であり、最も信頼性が高い情報源です。ただし非同期で時間がかかります。次に、SharedPreferences。ローカルにキャッシュした購入フラグで、高速に読めますが古くなる可能性があります。最後に、メモリ上の変数。リワード広告など一時的な状態を保持しますが、再起動後に消えます。

Antigravity が提案したのは「Google Play Billing を Source of Truth とし、それを包む AdFreeManager クラスに全判定を集約する」というアーキテクチャでした。なぜなら、購入状態は最終的に Google のサーバーが持つ情報が正であり、それ以外はすべてキャッシュや派生値に過ぎないからです。

この考え方を採用することで、「どこに聞けばいいか」が一か所に定まります。判定ロジックが変わるとき、修正は1か所だけです。バグを追うとき、調査は1か所から始まります。

✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦課金状態が複数箇所に散在してバグが頻発していた問題を、Source of Truthパターンで根本解決できる
✦BillingManager・AdFreeManager・ModalGateの3層設計を実装し、広告表示とペイウォール制御を一元化できる
✦Antigravityを活用したアーキテクチャ設計の思考プロセスを習得し、自分のアプリの設計課題に応用できる
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Antigravity Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

▣ アプリ開発2026-05-24
iOS Push 通知の A/B 運用を Antigravity Agent で週次回す — 文面・配信時刻・セグメントの自律改善ループ
個人開発で長く運用してきた壁紙系・癒し系アプリの実体験から、iOS Push 通知の A/B を Antigravity Agent に任せる週次運用設計をまとめました。FCM・Firebase Analytics・BigQuery の具体実装に加え、毎週の勝者宣言がどれだけ当たっているかを手元のシミュレータで測り、アーム数と判定条件を測定結果に合わせて直しています。
▣ アプリ開発2026-08-31
有料導線とレビュー訴求が重なるのを、ダイアログではなくゲートで止めています
有料プラン案内・レビュー訴求・リワード広告のダイアログが同じ瞬間に重なった実例から、表示可否の判断を各ダイアログから中央ゲートへ移した設計と、エージェントに不変条件を渡す指示の書き方、CI での機械検査までをまとめました。
▣ アプリ開発2026-08-18
API レベル 36 の期限に向けた、6本のアプリを上げる順番と段階公開の刻み方
Google Play の API レベル 36 要件は6本すべてに同じ期日で来ます。締切が同じなら決めるのは順番だけです。壊れやすさの棚卸しと、段階公開の刻み幅を必要観測数から逆算する手順をまとめました。