【Kotlin】AndroidアプリにAdMobインタースティシャル広告を実装する方法!画面遷移時の実戦向けコードも公開

AdMob

Androidアプリの収益化において、バナー広告よりも高い収益性(高eCPM)を期待できるのが「インタースティシャル広告(全画面広告)」です。しかし、適切なタイミングで読み込み(ロード)と表示(ショー)の管理を行わないと、「広告が表示されない」「アプリがフリーズする」「ユーザー体験(UX)を損ねる」といった問題に直面しがちです。

本記事では、Google Mobile Ads SDK(AdMob)を使い、Kotlinで安全かつ効率的にインタースティシャル広告を管理・実装する手順を、実践的なクラス設計とともに徹底解説します!

1.インタースティシャル広告の実装フローと準備

インタースティシャル広告を表示するまでの大まかな流れは以下の3ステップです。

  1. 広告のロード(事前準備): 画面が表示される前や、ユーザーのアクションの裏(バックグラウンド)で広告データをダウンロードしておく。
  2. 広告の表示(コールバック設定): ユーザーの操作(ゲームオーバー、ステージクリア、ボタンタップなど)のタイミングで全画面表示する。
  3. 広告クローズ後の処理(再ロードと次のアクション): 広告が閉じられたら、次の表示に備えて再ロードし、本来行いたかったアプリの処理を再開する。

📌 前提条件

  • Android Studioがインストールされていること
  • プロジェクトにAdMobのSDK(com.google.android.gms:play-services-ads)が導入されていること
  • AndroidManifest.xmlにAdMobのアプリケーションIDが正しく設定されていること

また、文字列リソース(strings.xml)に、テスト用または本番用の広告ユニットID(admob_unit_id)を定義しておきましょう

2.コピペで使える!インタースティシャル広告管理クラス

広告の「ロード」や「表示」のロジックをActivityやFragmentに直接書くと、コードが肥大化してメンテナンスが大変になります。 そこで、広告のライフサイクルを一括管理できる「マネージャークラス(InterstitialAdManager)」を作成するのがベストプラクティスです。

以下が、そのまま使える実装コードです

 package com.example.myapp
import android.app.Activity
import android.util.Log
import com.google.android.gms.ads.AdError
import com.google.android.gms.ads.AdRequest
import com.google.android.gms.ads.FullScreenContentCallback
import com.google.android.gms.ads.LoadAdError
import com.google.android.gms.ads.interstitial.InterstitialAd
import com.google.android.gms.ads.interstitial.InterstitialAdLoadCallback

class InterstitialAdManager(private val activity: Activity) {

    private var mInterstitialAd: InterstitialAd? = null
    private val TAG = "InterstitialAdManager"

    // テスト用インタースティシャル広告ユニットID
    private val adUnitId: String by lazy {
        activity.getString(R.string.admob_unit_id)
    }

    /**
     * 広告をバックグラウンドでロード(準備)する
     */
    fun loadAd() {
        // 💡 広告IDが本当に取得できているかログに出力する
        Log.d("AdCheck", "現在読み込もうとしている広告IDはこれです: $adUnitId")
        val adRequest = AdRequest.Builder().build()

        InterstitialAd.load(activity, adUnitId, adRequest,
            object : InterstitialAdLoadCallback() {
                override fun onAdFailedToLoad(adError: LoadAdError) {
                    Log.d(TAG, "広告の読み込みに失敗しました: ${adError.message}")
                    mInterstitialAd = null
                }

                override fun onAdLoaded(interstitialAd: InterstitialAd) {
                    Log.d(TAG, "広告の読み込みに成功しました。")
                    mInterstitialAd = interstitialAd
                }
            })
    }

    /**
     * 広告を表示する
     * @param onAdClosed 広告が閉じられた、または表示できなかった時に実行したい本来の処理(コールバック)
     */
    fun showAd(onAdClosed: () -> Unit) {
        if (mInterstitialAd != null) {
            // 広告のイベントを設定
            mInterstitialAd?.fullScreenContentCallback = object : FullScreenContentCallback() {
                override fun onAdDismissedFullScreenContent() {
                    Log.d(TAG, "広告が閉じられました。")
                    mInterstitialAd = null
                    loadAd() // 次のために再ロード
                    onAdClosed() // 本来の処理を実行
                }

                override fun onAdFailedToShowFullScreenContent(adError: AdError) {
                    Log.d(TAG, "広告の表示に失敗しました。")
                    mInterstitialAd = null
                    loadAd()
                    onAdClosed() // 失敗してもアプリが止まらないように次の処理へ
                }
            }
            // 広告を表示
            mInterstitialAd?.show(activity)
        } else {
            Log.d(TAG, "❌ 広告を表示しようとしましたが、まだダウンロードが完了していません(nullです)。")
            loadAd()
            onAdClosed() // 広告を出さずに次の処理へ
        }
    }
}

3.コードの重要なポイントを徹底解説!

このコードには、実務でアプリを運用する上で絶対に外せない工夫がいくつも施されています。

① 高速化のための「Lazyロード(遅延評価)」

adUnitId の取得に by lazy を使用しています 。これにより、InterstitialAdManager が生成された瞬間ではなく、実際に loadAd() が呼ばれてIDが必要になったタイミングで初めて strings.xml からIDを読み込みます 。無駄なメモリ消費を抑え、パフォーマンス向上に寄与します。

② 高いユーザー体験を実現する「ラムダ式(高階関数)コールバック」

showAd(onAdClosed: () -> Unit) という設計がこのコードの最大の強みです 。 全画面広告は、表示された瞬間にアプリの処理を一時停止し、閉じられたら「次のステージに進む」「画面を遷移する」といった本来の処理を再開させる必要があります。

この「本来の処理」を引数(関数)として渡せるようにしておくことで、広告が表示できても、表示に失敗しても、ロードが間に合わなくても、必ずユーザーは次の画面へ進めるよう安全弁が機能します

③ ユーザーを待たせない「自動再ロード機能」

広告が正常に閉じられた(onAdDismissedFullScreenContent)タイミングや、表示に失敗したタイミングで、即座に loadAd() を呼び出しています 。 これにより、ユーザーがアプリを操作している間に裏で次の広告が準備されるため、次回表示時の「広告がまだダウンロードされていません(null)」という機会損失を高確率で防ぐことができます

4. Activity側での具体的な使い方(実装例)

作成した InterstitialAdManager を、実際のActivityでどのように呼び出すのか、具体的な実装例を見てみましょう。

class MainActivity : AppCompatActivity() {

    private lateinit var adManager: InterstitialAdManager

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // マネージャーの初期化と、最初の広告ロード
        adManager = InterstitialAdManager(this)
        adManager.loadAd()

        // 例えば「次の画面へ進む」ボタンをタップした時
        val nextButton: Button = findViewById(R.id.btn_next)
        nextButton.setOnClickListener {
            
            // 広告を表示。閉じられた後の処理を {} 内に記述する
            adManager.showAd {
                goToNextScreen()
            }
        }
    }

    private fun goToNextScreen() {
        // 次の画面への遷移処理など、本来やりたいアクション
        val intent = Intent(this, SecondActivity::class.java)
        startActivity(intent)
    }
}

このように、Activity側のコードが非常にスッキリします。ボタンを押した際、広告があれば全画面で表示され、閉じられた瞬間に goToNextScreen() が実行されます。もし広告の読み込みが間に合っていなければ、広告を出さずに即座に goToNextScreen() が呼ばれるため、ユーザーを無駄に待たせることがありません。

5. 【超重要】リリース前に必ず設定!ProGuard(難読化)の回避策

デバッグ中は広告がちゃんと動いていたのに、「Google Playストア用に製品ビルド(Release)したら広告が一切表示されなくなった!」というトラブルは非常に多く発生します。

原因のほとんどは、コードの最適化・難読化を行う「ProGuard(R8)」が、AdMobの内部コードを「不要なコード」と勘違いして削除・リネームしてしまうことにあります。

この問題を解決するために、プロジェクトの proguard-rules.pro ファイルに以下の設定を必ず追記してください。

# --- WorkManager の難読化回避 ---
# バックグラウンド処理を行うWorkManagerのクラスが消されないように保護します
-keep class androidx.work.** { *; }

# --- 【重要】AdMob (Google Mobile Ads SDK) の難読化回避 ---
# AdMobが内部で使用するクラスやメソッドの名前が変わってしまうのを防ぎ、
# リリースビルドで「広告が表示されない」という致命的なバグを完全に予防・解決します
-keep public class com.google.android.gms.ads.** {
   public *;
}
-keep public class com.google.ads.** {
   public *;
}

# --- Android Startupライブラリの保護 ---
# アプリ起動時の初期化処理を最適化するライブラリの誤動作を防ぎ、安全性を高めます
-keep class androidx.startup.** { *; }

💡 なぜ -keep が必要なの?

AdMobなどの外部SDKは、AndroidシステムやGoogle Play開発者サービスと「反射(Reflection)」という仕組みを使って連携しています。ProGuardによってクラス名やメソッド名が(ab などの無意味な名前に)書き換えられてしまうと、Googleのシステムがアプリ内のAdMobコードを見つけられなくなり、エラー(広告が表示されない等)が発生します。

上記の -keep 構文は、「このパッケージ配下のクラスやメソッドは、リリース時も名前を変えずにそのまま残してね!」とコンパイラに指示を出すための重要な役割を持っています。

6. よくあるトラブル「広告が表示されない」ときのチェックリスト

実装中に「ログにエラーが出る」「広告が表示されない」となった場合は、以下のポイントを確認してください。

  1. 広告ユニットIDの間違い
    • テスト中は必ずGoogleが提供している「テスト用広告ユニットID」を使用してください。本番用のIDをテストで使用したり、自分の広告を何度もクリックしたりすると、AdMobアカウントがポリシー違反で凍結される恐れがあります。
  2. ロードから表示までの時間が短すぎる
    • アプリ起動直後に loadAd() を呼び、その1秒後に showAd() を呼んでも、通信環境によってはダウンロードが完了していません。必ず余裕を持ったタイミングで事前にロードしておきましょう。
  3. 初期化(MobileAds.initialize)の不備
    • InterstitialAd.load を呼ぶ前に、アプリ起動時(Application クラスや最初のActivityの onCreate)で MobileAds.initialize(this) {} が実行されているか確認してください。

まとめ:適切な実装で収益最大化を目指そう!

AdMobのインタースティシャル広告は、正しく実装すればアプリの収益を大きく支える柱になります。今回紹介したマネージャークラスの設計を取り入れることで、メモリリークを防ぎ、UXを損なわずに安全な広告運用が可能になります。

ぜひご自身のアプリに組み込んで、快適なアプリ開発&収益化ライフを送ってください!

なお現在はAndroidアプリをリリースするのに12人以上のテスターが必要です。もし身近にテスターをしてくれる方がいないようなら下記ココナラで依頼してみましょう。大体4000円くらいで依頼できます。


コメント

タイトルとURLをコピーしました