◉CLAUDE LABEN
●2.1.310 — Bedrock・Vertex・Foundry でも Monitor ツールが使え、ゲートウェイの失敗を修正しました(10/23)●2.1.307 — スリープやキーチェーンロックのあとに MCP が再接続されない問題を修正しました(10/21)。2.1.306 では claude -p の誤表示も解消●SONNET 4.5 — Claude API での提供終了は 11/30、残り36日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●API — 新しい API バージョン 2026-10-21 では temperature・top_p・top_k を渡すと 400 になります●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました●2.1.310 — Bedrock・Vertex・Foundry でも Monitor ツールが使え、ゲートウェイの失敗を修正しました(10/23)●2.1.307 — スリープやキーチェーンロックのあとに MCP が再接続されない問題を修正しました(10/21)。2.1.306 では claude -p の誤表示も解消●SONNET 4.5 — Claude API での提供終了は 11/30、残り36日。移行先は Sonnet 5.5●WINDOWS — 日本語の環境でだけフックが黙って壊れる報告があり、文字コードの確認が呼びかけられています●API — 新しい API バージョン 2026-10-21 では temperature・top_p・top_k を渡すと 400 になります●NEW — Cowork に渡したフォルダの先頭に、十行の約束ファイルを置いてみました
記事一覧/Claude Code
⟐ Claude Code/2026-06-12中級

Android の戻るボタン広告ゲートを入れ子から並列独立構造へ — Claude Code と進めた終了フロー再設計の記録

戻るボタンの広告が「出ない」と「出すぎる」を同時に起こした原因は、入れ子分岐に埋め込まれた暗黙の優先度でした。壁紙アプリ v2.1.0 で広告ゲートを並列独立構造へ作り直した過程を、Kotlin実装・Claude Codeへの依頼内容・テストまで含めて記録します。

claude-code132android9admobkotlin3refactoring

✦ プレミアム記事

2026年5月、運営している壁紙アプリの Android 版 v2.1.0 を準備していたとき、相反する2つのシグナルが同時に届きました。ストアレビューには「終了するたびに広告が出る」という声。一方で AdMob の管理画面を見ると、終了時インタースティシャルの表示回数は想定の半分ほどしかありません。「出すぎている」と「出ていない」が、同じバージョンに対して同時に報告されている状態です。

この時点で、原因が広告 SDK 側ではなく自分のコードの分岐ロジックにあることをほぼ確信しました。実際の犯人は、戻るボタンの処理に何年もかけて積み重なっていた入れ子の条件分岐です。ここに記録するのは、その入れ子をゲート単位の並列構造へ作り直し、分岐パスの棚卸しとテスト生成を Claude Code に任せた約2週間の作業内容です。同じように「終了時の広告まわりだけ誰も触りたがらない」状態になっているアプリは少なくないと思いますので、設計の考え方と移行の手順をそのまま共有します。

症状 — 「出ない」と「出すぎる」が同じ終了フローから生まれていた

問題の画面はアプリのトップ画面です。ここで戻るボタンが押されたとき、アプリは次の5つの問いに答える必要がありました。

  • 広告非表示ユーザーか: 買い切りの広告除去を購入済みか、リワード広告視聴による一時的な広告フリー期間中か
  • 他のモーダルが出ていないか: レビュー誘導やお知らせダイアログと重ならないか
  • レビュー誘導を出す条件を満たしているか: 起動回数や前回表示からの経過日数
  • 表示間隔の上限に達していないか: 終了時広告のフリークエンシーキャップ
  • インタースティシャルがロード済みか: 未ロードなら何も出せない

5つと書くと整理されて見えますが、実際のコードではこれらが約10年分の機能追加の順番どおりに、入れ子の if 文として埋まっていました。そして観測された不具合は2系統です。ひとつは、レビュー誘導の表示フラグが立ったまま降りない経路があり、その状態に入ったユーザーには終了時広告が一切出なくなるもの。もうひとつは、広告が未ロードだった場合の素通し経路でフリークエンシーキャップの計測が更新されず、次回セッションで本来の間隔を無視して広告が出るものです。前者が AdMob レポート上の「出ない」を、後者がレビュー欄の「出すぎる」を作っていました。

原因 — 入れ子の if は優先度を暗黙のうちに固定する

リファクタリング前のコードを、変数名だけ整えて簡略化するとこういう形でした。

// Before: 戻るボタン処理に積み重なっていた入れ子分岐(実物を簡略化)
override fun onBackPressed() {
    if (!billingManager.isPurchased) {
        if (interstitialAd != null) {
            if (!reviewInduction.isShowing) {
                if (frequencyCap.canShow()) {
                    interstitialAd?.show(this)      // ようやく広告表示
                } else {
                    super.onBackPressed()           // 上限到達 → 素通し
                }
            }
            // reviewInduction.isShowing == true のときは何もしない(バグの温床)
        } else {
            super.onBackPressed()                   // 未ロード → 素通し(計測漏れ)
        }
    } else {
        super.onBackPressed()                       // 課金済み → 素通し
    }
}

このコードの問題は、バグが2件あることそのものではありません。構造として次の3つの性質を持ってしまっていることです。

第一に、優先度がネストの深さに埋め込まれていて、仕様として読めないことです。「課金判定はレビュー誘導より強い」「レビュー誘導は広告より強い」という業務上の優先順位が、コードの字面からは「たまたまその順に書かれている」ようにしか見えません。新しい条件を足すとき、どの深さに差し込むべきかを判断する材料がコードの中にないのです。

第二に、条件が1つ増えるたびに経路が倍々で増えることです。boolean の条件が5つあれば理論上の状態は32通りで、そのすべてに「何が起きるべきか」の答えがあるはずですが、入れ子構造では書かれていない組み合わせが else の谷間に落ちます。落ちた先が super.onBackPressed() なのか「何もしない」なのかは、たまたまどの else に拾われるか次第です。

第三に、素通しの経路が無言であることです。広告が出なかったとき、それが課金済みだからなのか、未ロードだからなのか、キャップ到達なのかをログから区別できませんでした。「出ない」系の不具合調査が毎回難航していた直接の理由です。

個人開発を2014年から続けてきて、この種の「動いているから触らない」コードが一番高くつくことは身に染みているのですが、終了フローは確認の手間が大きく、後回しにし続けていました。今回 Claude Code に分岐パスの列挙を任せられたことが、重い腰を上げるきっかけになりました。

✦

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

この記事の続きを読む

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

この記事で得られること
✦戻るボタン広告の「出ない・出すぎる」をゲート単位で切り分け、ログから数分でどのゲートが原因かを特定できるようになる
✦入れ子の if 文を「優先度リスト + 先勝ち評価」の並列独立ゲートへ置き換える Kotlin 実装と、5つの移行手順を持ち帰れる
✦isAdFree || isRewardAdFree を単一の Source of Truth に集約し、課金とリワード解除の判定ずれを構造的に防げるようになる
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

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

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

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

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

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

関連記事

⟐ Claude Code2026-05-27
壁紙アプリ 2 本の Crashlytics を Claude Code で 11 日間掘り続けた実装ログ
壁紙アプリ 2 本(綺麗な壁紙 v2.0.0 / 浮世絵壁紙 v1.7.0)でリリース後に Crashlytics と Play Console から噴き出した 30 件超のバグを、Claude Code で 11 日間掘り続けて v2.1.1 / v1.8.1 まで仕上げた工程を、スタックトレース → 原因仮説 → 修正コミットの順で公開します。
⟐ Claude Code2026-08-28
名前に混ざった見えない文字を、プラグインを入れる前に洗い出す小さなスクリプト
プラグインやスキルの名前に不可視文字や制御文字が混ざっていても、ターミナルの一覧では見分けがつきません。実際に6つの紛らわしい名前を並べて ls の出力を比べ、導入前に走らせる点検スクリプトと、その点検が拾えない範囲までを整理しました。
⟐ Claude Code2026-08-26
キャッシュのTTLを1時間に延ばすかは、離席の長さではなく戻る場所で決めています
Claude Code v2.1.242 で promptCacheTtl と subagentPromptCacheTtl が追加されました。1時間キャッシュが効く条件は離席時間ではなく、同じ作業ディレクトリと同じ git 状態へ戻るかどうかです。判断の順番と、効いているかを確かめる手順を書き残します。