RORK LABEN
TOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しましたTOOLING — Rorkの開発者向けリポジトリが動き続けています。rork-xcodeが7月16日、rork-deviceが7月15日、rork-plistが7月13日に更新されましたOPUS46 — RorkでClaude Opus 4.6が稼働しています。Rork MaxはClaude Codeを土台にアプリを組み立てる設計ですSIM — ブラウザ上で動くクラウドのiOSシミュレータを備え、実機へのインストールは1クリック、App Storeへの提出は2クリックと案内されていますMAX — Rork MaxはReact Nativeではなく純粋なSwiftを出力します。iPhone・iPad・Apple Watch・Apple TV・Vision Pro、そしてiMessageまでが射程ですNATIVE — HealthKit、ARKitとLiDAR、NFC、Dynamic Island、Live Activities、Metalによる3D、Core MLのオンデバイス推論まで扱えますSEED — RorkはLeft Lane Capitalが主導する1,500万ドルのシードラウンドを実施し、Peak XVとa16z Speedrunが参加しました
記事一覧/開発ツール
開発ツール/2026-05-16中級

Rorkアプリの広告ゲートを入れ子で書くと詰まる理由 — 並列構造とad-free Source of Truthで解決した話

Beautiful HD Wallpapersのv2.1.0更新で踏んだ広告ゲートの入れ子バグ。並列独立構造とad-free Source of Truthに書き直したら、Rorkで生成したコードにも同じ改善が適用できました。

AdMob70Android43広告実装2個人開発186Rork515

Beautiful HD Wallpapers の v2.1.0 を準備していたとき、特定の操作手順でだけ戻るボタンを押しても広告が表示されないバグに気づきました。コードを追うと原因はすぐ分かりましたが、修正に手間取りました。onBackPressed の中で「広告フリーかどうか」と「表示タイミングかどうか」の判定が入れ子になっていて、片方を直すともう一方のケースが壊れる状態になっていたからです。

累計5,000万DL超のアプリを個人で運営してきた中で何度か踏んできた罠ですが、同じパターンがRorkで生成したコードにも出やすいことに気づいてから、設計方針を明文化しました。このパターンは再現しやすく、かつ原因が分かりにくいため、備忘も兼ねて記録しておきます。

入れ子のad gateが引き起こす問題

問題のあったコードを簡略化するとこんな形です。

// ❌ 入れ子構造(問題あり)
override fun onBackPressed() {
    if (isAdFree) {
        super.onBackPressed()
    } else {
        if (shouldShowAd()) {
            showInterstitial {
                super.onBackPressed()
            }
        } else {
            super.onBackPressed()
        }
    }
}

一見シンプルですが、後から「報酬広告を視聴してad-freeになった場合」を追加しようとすると、どの if ブロックの内側に入れるかが曖昧になります。isAdFreetrue のケースにまとめるべきか、あるいは shouldShowAd() の手前に割り込ませるべきか、コードを書いている側は判断できますが、読み返したときには分かりにくくなっています。

入れ子構造の根本的な問題は、条件の優先順位が暗黙になることです。分岐を追う際に全体のツリーを頭の中で展開する必要があり、新しい条件を追加するたびにその認知コストが増えます。Beautiful HD Wallpapers の場合、v2.0.0 から v2.1.0 の更新で「報酬広告視聴後の免除」ロジックを追加したときに、既存の入れ子に差し込む位置を一箇所間違えて、特定の遷移フローだけ広告が出ないバグが発生しました。

並列独立構造への書き直し

修正したコードはこうなりました。

// ✅ 並列独立構造(改善後)
override fun onBackPressed() {
    when {
        isAdFree -> {
            // 課金または報酬視聴済み → 広告なしで戻る
            super.onBackPressed()
            return
        }
        shouldShowAd() -> {
            // 広告表示タイミング → インタースティシャル表示後に戻る
            showInterstitial { super.onBackPressed() }
            return
        }
        else -> {
            // それ以外(クールダウン中など)→ そのまま戻る
            super.onBackPressed()
        }
    }
}

when ブロックで条件を横並びにすると、各ケースが独立して読めます。新しい条件(「特定の画面では広告を出さない」「デバッグビルドでは広告をスキップ」)を追加する際も、既存の分岐に触れずに追記できます。

各ブランチに return を明示しているのがポイントです。入れ子のときは return の位置が暗黙でしたが、並列にすることで「このケースはここで完結する」という意図が明確になります。コードレビューや3ヶ月後の自分が読んだときに、意図が伝わるかどうかを個人開発では特に重視しています。チームのレビューアがいない分、未来の自分が唯一の読者になるからです。

ad-free状態のSource of Truthを一箇所に集める

入れ子バグの第二の根本原因は、isAdFree の判定がコード内の複数箇所に散らばっていたことです。課金状態(BillingManager)と報酬広告の視聴状態(AdFreeManager)を別々に参照していたため、一方が更新されたときに同期漏れが起きました。

修正後は、判定ロジックを一箇所に集約しました。

// AdFreeManager — 広告フリー判定のSource of Truth
class AdFreeManager(
    private val billingManager: BillingManager,
    private val rewardAdManager: RewardAdManager
) {
    val isAdFree: Boolean
        get() = billingManager.isPremiumUser || rewardAdManager.isRewardAdActive
 
    val shouldShowAd: Boolean
        get() = !isAdFree
}

onBackPressed からは adFreeManager.isAdFree だけを参照します。課金状態と報酬状態のどちらが変わっても、このクラスだけを更新すれば全体に反映されます。個人開発を12年続けてきて実感するのは、「同じことを複数の場所で判定しているコード」は必ずある時点でずれる、ということです。ad-free の判定はユーザーの支払い体験に直結するため、Source of Truth を一箇所にまとめることが特に重要です。

RorkとAIアシスタントへの依頼の仕方

Rorkで AdMob を組み込んだアプリを生成すると、広告の表示ロジックが入れ子になって出てくることがあります。特に「課金ユーザーは広告を出さない」という要件を後から追加したとき、AIが既存の if ブロックの内側にネストする形で条件を追加しやすい傾向があります。

生成されたコードを受け取った後に自分で書き直すか、Rorkに対して構造を具体的に指定します。

「広告ゲートのロジックを並列構造(when ブロック)で書き直してください。
isAdFree / shouldShowAd / else の3ケースを独立させ、
各ブランチに return を明示してください。
ad-free判定は BillingManager と RewardAdManager を合成した
AdFreeManager クラスに一元化してください」

「入れ子を避けて」だけでは判断が難しいため、when ブロックという具体的な構文と、ケース名、クラス名まで一緒に伝えるのがポイントです。Rorkは指示が具体的であれば、並列構造のコードを正しく出力します。私はこのアプローチを Ukiyo-e Wallpapers の Android 版リニューアルでも使いましたが、当初の生成結果を受け取った後に上記の指示で再生成させたところ、レビューなしで使えるコードが出てきました。

v2.1.0適用後に変わったこと

Beautiful HD Wallpapers の v2.1.0 でこの修正を適用してから、広告関連のバグ報告がゼロになりました。以前は月に1〜2件あった「広告が出ない」「広告が出すぎる」という報告が消え、カスタマーサポートの負荷が下がっています。

コードレビューの観点でも変化があります。ad-gate のロジックを読む際に when の各ブランチを上から順に追えばよくなったため、新機能追加時の確認時間が短くなりました。個人開発では実装とレビューが同一人物なので、「未来の自分がすぐ読める」かどうかがコードの品質基準になります。入れ子を並列に直した後のコードは、その基準を明確に満たしています。

ad-free判定が絡む広告ゲートを実装しているなら、まず grep -r "if.*isAdFree" src/ で入れ子パターンを探してみてください。入れ子になっている箇所が見つかれば、今日から並列構造へ書き直す価値があります。

なぜこのパターンが繰り返されるのか

入れ子のad gateは、最初に書くときには合理的に見えます。「広告フリーなら戻る、そうでなければ広告条件を確認する」という日本語の論理をそのままコードに落とすと、自然と入れ子になります。公式のAdMobサンプルコードも入れ子で書かれていることがあり、それを参考にすると同じ構造になりやすいです。

問題が顕在化するのは、ほとんどの場合「後から条件を追加したとき」です。初期リリースでは課金ユーザーだけad-freeにすれば十分だったのが、報酬広告の免除、A/Bテスト中の広告スキップ、特定画面での広告抑制、開発時のデバッグフラグ——こういった要件が積み重なるにつれて、入れ子の深さが増していきます。

個人開発では、アプリを長期間运営していると必ずこの状況に直面します。Beautiful HD Wallpapers は2013年にリリースして12年以上経っており、ad-gate のロジックには様々な時代の判断が積み重なっていました。並列構造への書き直しは、そのコードの歴史を整理する作業でもありました。

全体を振り返ってと次のアクション

入れ子のad gateを並列構造に書き直すだけで、コードの可読性と保守性が大きく改善されます。Rorkで生成したコードを受け取った後にも、この観点でのレビューを習慣にすることをおすすめします。

既存コードに入れ子のad gateがないか、まず grep -r "if.*isAdFree" src/ または grep -r "isAdFree" app/ で確認してみてください。ヒットした箇所を when ブロックに書き換えることが、今日からできる最初のステップです。

ad-free状態の Source of Truth については、アプリのビジネスロジックの中心に置くほど効果があります。広告表示だけでなく、プレミアム機能の解放可否や特定のUIの表示制御など、「課金状態を参照したい場面」が増えるほど、AdFreeManager のような一元管理クラスの価値が高まります。最初から設計しておくか、後から段階的に移行するかは開発フェーズによりますが、広告収益が中心のアプリでは早い段階で導入しておく方が後の作業を大きく減らせます。Rorkとのやり取りでこの設計を共有しておくことで、AIが生成するコードの品質も自然と上がります。

シェア

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

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

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

もしこの記事がお役に立ちましたら、チップ(¥150)で応援いただけると大変励みになります。広告なしでの運営を続けるため、皆さまのご支援が大きな力になっています。

関連記事

開発ツール2026-05-17
Rork のコード生成は本番に使えるか — 累計5,000万DL開発者が実機テストで見つけた3つの落とし穴
累計5,000万DLのアプリを運営してきた視点から、Rorkが生成するコードを実機テストして分かった3つのクラッシュパターンと対処法を整理しています。Rorkを本番に使う前に確認すべきポイントを具体的なコード例とともに解説します。
開発ツール2026-05-26
Rork で生成した壁紙アプリを iPad へ対応させた2週間の所感
2014年から壁紙アプリを iPhone 中心で運用してきた個人開発者として、Rork で立ち上げた新規壁紙アプリを iPad に対応させる作業を2週間続けた記録です。AdMob アダプティブバナーの暴れ方、Safe Area の盲点、グリッド表示の解像感まで、運用の温度のまま書き残しました。
開発ツール2026-05-26
App Store Connect・RevenueCat・AdMob の朝の指標を Cloudflare Workers で1本化する — 6アプリ運用の日次集約アーキテクチャ
Rork で複数アプリを運用する個人開発者向けに、App Store Connect API・RevenueCat REST・AdMob Reporting API を Cloudflare Workers Cron で集約し、毎朝1通の日次レポートに統合する実装手順をまとめました。
📚RECOMMENDED BOOKS
大規模言語モデル入門
山田育矢
LLM開発
生成AIプロンプトエンジニアリング入門
我妻幸長
プロンプト
Claude CodeによるAI駆動開発入門
平川知秀
AI駆動開発
※ アフィリエイトリンクを含みます
もっと見る →