UnityでAdMobをGDPR対応させる(その5)

AdMob for GDPR Unityプログラミング

前回はGDPR同意取得の全体フローを解説しました。今回は具体的なコードを解説します。コードは私が試行錯誤で完成させたものですので、ガラパゴス化しているかもしれません。また、この記事には、極端な表現や矛盾や説明の不足や表現が一致しない箇所があるかもしれません。色々と大目に見ていただけると助かります。

使用するバージョン

Unity6000.3.8f1
Google Mobile Ads Unity Plugin v11.2.0

はじめに

前回から今回まで2ヶ月ありましたので少しコードを簡素化できました。前回ご紹介したフローと今回のコードが一致しない場合は、申し訳ないです。今回(その5)と次回(その6)のコードを実装すると、Unityのエディタ上でゲームを再生したときに以下のデモ用フォームが表示されるはずです。表示を目指して、頑張ってコーディングしていきましょう!

GDPR form

注意点

注意すべき点がいくつかあります。

注意点
  1. インターネット接続確認は自前クラスですること
  2. 実機確認の前にAdMob管理画面で「メッセージの作成」をしておくこと
  3. 「メッセージの作成」では日本語など欧米以外の言語は選択しないこと
  4. 実機確認の際はダミー広告ではなく本番広告をテストモードで使用すること

1については後述します。2については事前作成しておかなければ、例えテストであっても同意フォームが実機で表示されずエラーになります。3については日本語の同意フォームを実機で表示すると高確率で通信が失敗します。英語バージョンを表示するようにしましょう。4についてはダミー広告だと同意取得後に広告が表示されないことがあります。落とし穴が満載ですね。

メッセージの作成方法

AdMob管理画面の「プライバシーとメッセージ」の「欧州の規制」の「管理」ボタンを押した先で、「メッセージの作成」を行うことができます。以下のスクショを参考にしてください。

GDPRフォームの作成方法

GDPR対応させたAdMob表示メソッド

GDPRに対応させたAdMob表示メソッド(=GDPR同意取得メソッド)は以下の通りです。次回の記事で説明するクラスやメソッドもありますが、気にせず全体を眺めてください。

    // 広告が開始済みであることを示す
    static bool Ad_Already_Started = false;


    // GDPRに対応させたAdMob表示メソッド
    public static void TryAdMob()
    {
        if (TryAdMob_Busy || Ad_Already_Started) return;
        TryAdMob_Busy = true;
        Instance.StartCoroutine(TryAdMob_Event());
    }


    // GDPRに対応させたAdMob表示メソッドのコアな部分
    public static bool TryAdMob_Busy = false;
    static IEnumerator TryAdMob_Event()
    {
        Debug.Log($"TryAdMob Start");

        // 0.すでに広告が開始されている場合
        if (Ad_Already_Started)
        {
            Debug.Log($"TyAdMob Ad already started");
            LoadAdsIfNull();
            TryAdMob_Busy = false;
            yield break;
        }

        // 1.理由はわからないが最初から広告が許可されている場合
        if (ConsentInformation.CanRequestAds())
        {
            Debug.Log($"TryAdMob Ad Start");
            yield return AdFinalize();                          // 広告を開始する
            TryAdMob_Busy = false;
            yield break;
        }

        // 2.インターネット未接続の場合は処理をキャンセル
        bool isOnline = false;
        yield return InternetChecker.Check(x => isOnline = x);
        if (!isOnline)
        {
            Debug.Log($"TryAdMob Internet NG");
            TryAdMob_Busy = false;
            yield break;
        }

        // 3.同意状態を確認し、エラーの場合は処理をキャンセル
        bool? updateResult = null;
        yield return TryUpdate(x => updateResult = x);          // これはダミー広告だと初回失敗する
        if (updateResult == false)
        {
            Debug.Log($"TryAdMob Update NG");
            TryAdMob_Busy = false;
            yield break;
        }

        // 4.同意フォームを表示する
        bool? canShowAd = null;
        yield return TryShowForm(x => canShowAd = x);                       // デバッグの同意フォームは英語じゃないとエラーが返る

        // 5.広告表示処理
        if (canShowAd == true)
        {
            while (!ConsentInformation.CanRequestAds()) yield return null;  // 広告可能になるまで待つ
            yield return AdFinalize();                                      // 広告を開始する
        }

        Debug.Log($"TryAdMob FinalResult={canShowAd}");
        TryAdMob_Busy = false;
    }

いかがでしょう。思っていた感じとは違いましたか?とにかく処理が多いので、このコードでは深いネストを避け、極力わかりやすくしたつもりです。人によっては逆効果だったら、ごめんなさい。では、コードを上から順に解説していきます。

TryAdMobメソッド

GDPR対応したAdMobを表示するためのメソッドです。TryAdMob_Busyは二重実行防止のインターロックです。また、Ad_Already_StartedがTrueのとき、つまり広告表示が開始されているときは、実行をキャンセルします。そして、コアな処理はTryAdMob_Eventに丸投げします。

TryAdMob_Eventメソッド

コアな処理を行うコルーチンのメソッドです。コルーチンのことをここでは詳しく解説しませんが、所定時間待機したり、複数の処理を同時並行に行ったりする仕組みだと思ってください。Googleのサーバーに投げたリクエストのレスポンスは、いつどのタイミングで戻ってくるかわからないですよね。だから、いつまでも待てるようにコルーチンを使用しているのです。詳細についてはググってください。このメソッドでは次の処理を上から順に行います。

メソッド内の処理
  • 【1】広告表示可能か確認(念のため)
  • 【2】インターネット接続しているか確認
  • 【3】同意状態確認リクエスト
  • 【4】同意フォーム表示リクエスト
  • 【5】広告表示処理

では、処理を解説していきます。

広告表示可能か確認

ConsentInformation.CanRequestAds()で広告表示可能状態かどうかを確認し、結果がTrueであれば広告の初期化と表示を開始します。Falseの場合は同意フォームを出す必要があるということなので、TryAdMob_Eventメソッドの処理を継続します。なお、広告の表示にインターネット接続は必要ですが、広告の初期化にインターネット接続は必要ありません。

インターネット接続しているか確認

isOnlineというboolで結果を受け取ります。インターネット接続確認のメソッドInternetChecker.Checkの引数に関数x => isOnline = xを与えて実行します。この関数はラムダ式無名関数なので何だかわかりにくい印象がありますが、通常の関数として書き下すと、以下のようなありきたりなものだとわかります。

void Method(bool x)
{
  isOnline = x;
}

コルーチンというのは実は、戻り値がとれない処理なんです。でも処理結果を返して欲しい。だから、コルーチンであるInternetChecker.Checkになんとかして処理結果を返してもらうために、処理結果を引数のisOnlineへ代入させるということをやっています。isOnlineを通して処理結果をメソッド外でも確認できるというわけです。isOnlineがFalseだった場合は、TryAdMob_Eventを中止します。(InternetChecker.Checkについては後述します)

同意状態確認リクエスト

updateResultというboolで結果を受け取ります。同意状態確認リクエストするコルーチンのメソッドTryUpdateに関数x => updateResult = xを与えて実行します。updateResultがFalseだった場合は、TryAdMob_Eventを中止します。

同意フォーム表示リクエスト

canShowAdというboolで結果を受け取ります。同意フォーム表示リクエストするコルーチンのメソッドTryShowFormに関数x => canShowAd = xを与えて実行します。

広告表示処理

canShowAdがTrueの場合のみ広告表示を開始します。

インターネット接続を確認するクラスの詳細

インターネット接続を確認するクラスInternetCheckerについてはkanのメモ帳様の記事を参考に作成しました(kanのメモ帳様の記事)。インターネット接続を確認する方法をGoogleなどで検索するとApplication.internetReachabilityを使用する記事ばかりが出てきます。しかし、前述の記事にもある通り、これは端末の接続設定のOnOff状態を表しているに過ぎません。実はUnityではインターネット接続確認メソッドは用意されていないので、自作するしかありません。前述の記事を参考にクラスを自作できるようであれば、自作してください。無理なようでしたら、次回以降の記事で私が説明しますのでしばらくお待ちください。

同意状態確認リクエストのメソッド詳細

同意状態確認リクエストのメソッドであるTryUpdateの中身は以下の通りです。

    static IEnumerator TryUpdate(Action<bool?> callback)
    {
        bool? result = null;

        ConsentInformation.Update(MakeConsentParameters(), error =>
        {
            MobileAdsEventExecutor.ExecuteInUpdate(() =>
            {
                result = error == null; // nullじゃなければ合格

                if (result == false)
                {
                    Debug.Log($"TryUpdate Err: {error.Message}");
                }
            });
        });

        while (result == null) yield return null;          //処理が完了するまで待つ

        callback(result);
    }

TryUpdateの引数はboolを引数に持つデリゲートです。デリゲートというのは関数の変数のことです。resultはNull許容型のboolです。Null許容型のboolはNull, True, Falseの3つの状態を取ることができます。TryUpdateは、受け取ったデリゲートを実行することによって、resultの値をメソッド外に渡します。ConsentInformation.UpdateはGoogle純正の同意状態確認リクエストのメソッドです。ConsentInformation.Updateの処理結果にエラーがある時はresultにFalseを入れ、正常ならばresultにTrueを入れます。resultがNullでなくなるまでwhile (result == null) yield return nullによって待機することで、ConsentInformation.Updateの処理の完了を監視しています。(なお、while (result == null) yield return null;はwhile (result == null){ yield return null;}の略記です。)

そして、同意フォームの表示に必要なパラメータを作成するメソッドであるMakeConsentParametersの中身は以下の通りです。

    static ConsentRequestParameters MakeConsentParameters()
    {
        var parameters = new ConsentRequestParameters
        {
            TagForUnderAgeOfConsent = false,
            ConsentDebugSettings = new ConsentDebugSettings
            {
                DebugGeography = DebugGeography.EEA,
                TestDeviceHashedIds = UMP_TestDevices
            }
        };

        return parameters;
    }

    static readonly List<string> UMP_TestDevices = new()
    {
        "テストデバイスID",
    };

TagForUnderAgeOfConsentについては、ターゲットが13歳以上のアプリの場合、すなわちEUでGDPR同意フォームを表示する年齢以上の場合はfalseにしてください。13歳未満のアプリはtrueにしてください。我々のアプリではもちろんfalseですね!ConsentDebugSettingsは動作確認したいときだけ有効にし、動作確認が終わったらコメントアウトしてください。DebugGeography = DebugGeography.EEAを有効にすると日本にいながらGDPR同意フォームを表示することができます。ただし、実機の場合は、テストデバイスIDを正しく指定しないとGDPR同意フォームが表示されません。また、事前にAdMob管理画面から「メッセージの作成」をしておかないと表示されません。

注意点

罠なんですが、AdMobには2種類のテストデバイスIDがあります。1つはさっき説明したGDPR同意フォーム向けのテストデバイスID。もう一つは、本番広告をテストデバイスで表示するためのテストデバイスID。実はこの2つは全く別物です(←iOSの場合は別物。Androidの場合は同じになります。2025年9月25日時点)。前者のIDはいくつかハイフンが含まれる仕様です。後者はハイフンが全く含まれない仕様です。それぞれ実機確認の際に、コンソールに表示されますので、メモりましょう。2つのテストデバイスIDを混同しないよう注意しましょう。

同意フォーム表示リクエストのメソッド詳細

同意フォーム表示リクエストのメソッドであるTryShowFormの中身は以下の通りです。最初にConsentInformation.ConsentStatusを確認して結果に応じて処理を変えます。statusがConsentStatus.Requiredの時のみ、同意フォーム表示を行うようにしています。

    static IEnumerator TryShowForm(Action<bool> callback)
    {
        var status = ConsentInformation.ConsentStatus;

        Debug.Log($"TryShowForm CONSENTSTATUS={status}");

        if (status == ConsentStatus.Required)
        {
            // 同意フォームが可能になるまで待つ
            while (!ConsentInformation.IsConsentFormAvailable()) yield return null;

            bool? result = null;

            ConsentForm.LoadAndShowConsentFormIfRequired(error =>
            {
                MobileAdsEventExecutor.ExecuteInUpdate(() =>
                {
                    result = error == null;// nullじゃなければ合格

                    if (result == false)
                    {
                        Debug.Log($"TryShowForm Err: {error.Message}");
                    }
                });
            });

            while (result == null) yield return null;

            callback(result == true);
        }
        else if (status == ConsentStatus.Obtained || status == ConsentStatus.NotRequired)
        {
            callback(true);
        }
        else
        {
            //念の為
            callback(false);
        }
    }

statusがConsentStatus.Requiredの場合は最初に、同意フォームが利用可能になるまで待ちます。可能になれば、ConsentForm.LoadAndShowConsentFormIfRequiredメソッドで同意フォームの表示を試みます。resultはNull許容型のboolです。Null許容型のboolはNull, True, Falseの3つの状態を取ることができます。エラーがあるとresultにFalseを入れ、なければTrueを入れます。resultがNullである限り、値が入るまで待機します。

終わりに

少し記事が長くなりましたので、中身を紹介していないクラスやメソッドは次回以降とします。また、GDPRの規則では同意後の同意取消しも必須となっていますので、その対応も次回以降とします。

このシリーズの記事

☕ ブログを応援する

いつも記事をお読みいただきありがとうございます!
内容が役立った、応援したいと思っていただけた方は、サーバー代や活動費としてサポート(投げ銭・150円〜)をいただけると励みになります。

PayPalでサポートを送る (150円〜)

※いただいたサポート(投げ銭)の原則としての返金には対応いたしかねます。あらかじめご了承のうえ、温かいご支援をお願いいたします。

コメント

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