前回、GDPR同意取得のメソッドのコードについて粗方説明しました。今回は、前回説明できなかった次のメソッドの説明をします。
- グローバル設定と広告のロード(AdFinalize)
- インターネット接続確認(InternetChecker.Check)
ほとんどが私の我流のコードなので、ガラパゴス化しているかもしれません。また、この記事には、極端な表現や矛盾や説明の不足や表現が一致しない箇所があるかもしれません。色々と大目に見ていただけると助かります。
Unity6000.3.8f1
Google Mobile Ads Unity Plugin v11.2.0
グローバル設定と広告のロード
すべての広告に使用されるグローバル設定
すべての広告に使用されるグローバル設定を、広告のロード前に必ず行います。前回の記事のTryAdMob_Eventの「5.広告表示処理」のAdFinalizeがその設定を行うメソッド(最初の部分)です。中身は以下の通りです。
static IEnumerator AdFinalize()
{
// すべての広告に使用されるグローバル設定=======================
var request = new RequestConfiguration()
{
TagForChildDirectedTreatment = TagForChildDirectedTreatment.False,
MaxAdContentRating = MaxAdContentRating.T,
};
MobileAds.SetRequestConfiguration(request);
MobileAds.SetiOSAppPauseOnBackground(true);//iOSでフルスクリーン広告が表示されている間、Unityアプリを一時停止
// 広告の初期化===========================================
bool? result = null;
MobileAds.Initialize(initstatus =>
{
result = initstatus != null; // nullでなければ合格
});
while (result == null) yield return null;//結果を待つ
// 広告のロード===========================================
if (result == true)
{
Ad_Already_Started = true; //広告表示に関係するのでこの位置
LoadAdsIfNull();
}
}
コードを上から順に解説します。
var request = new RequestConfiguration()が、すべての広告に使用されるグローバル設定の設定内容です。RequestConfigurationのプロパティのTagForChildDirectedTreatmentは、アメリカCOPPAの「子ども」に該当するかどうかの設定です。COPPAはアメリカ版のGDPRみたいなものですが、GDPRではありません。なので、記事のテーマである”GDPR対応”とは関係ありませんが、ついでですので設定しておきましょう。13歳未満のアプリの場合はTagForChildDirectedTreatment.Trueを代入します。13歳以上のアプリはTagForChildDirectedTreatment.Falseを代入します。我々のアプリは後者でしょう。そして、もう一つのプロパティのMaxAdContentRatingは、広告のレーティングの設定です。レーティングの種類は以下の4つです。
- MaxAdContentRating.G(一般ユーザー)
- MaxAdContentRating.PG(保護者の判断を推奨)
- MaxAdContentRating.T(13歳以上)
- MaxAdContentRating.MA(成人)
我々のアプリはMaxAdContentRating.TかMaxAdContentRating.MAでしょう。これと同様の設定をAdMob管理画面でも行えます。ただし、MaxAdContentRatingとAdMob管理画面の設定が食い違う場合は、MaxAdContentRatingが優先されることに注意が必要です。
MobileAds.SetRequestConfiguration(request)が、前述の設定内容で設定を行うメソッドです。
MobileAds.SetiOSAppPauseOnBackground(true)はiOSでフルスクリーン広告が表示されている間、Unityアプリを一時停止するためのメソッドです。Androidの場合は処理が無視される仕様となっていますので、OSの違いで場合分けする必要はありません。つまり、Androidの場合もそのまま消さなくて大丈夫です。
広告の初期化とロード
広告の初期化とロード処理はAdFinalizeの後半部分です。以下の部分です。
// 広告の初期化===========================================
bool? result = null;
MobileAds.Initialize(initstatus =>
{
result = initstatus != null; // nullでなければ合格
});
while (result == null) yield return null;//結果を待つ
// 広告のロード===========================================
if (result == true)
{
Ad_Already_Started = true; //広告表示に関係するのでこの位置
LoadAdsIfNull();
}
コードを解説します。MobileAds.InitializeはAdMobの初期化メソッドです。このメソッドの引数のラムダ式はデリゲートです。初期化メソッド実行後にこのデリゲートが実行されます。処理が正常に終わればinitstatusはnullではありません。よって、initstatusがnullのときはresultにFalseを、nullでなければresultにTrueを代入しています。そして、resultがTrueの場合のみ、BannerManager.Instance.LoadAdでバナー広告のロードを行います。同じタイミングでAd_Already_StartedにTrueを入れて「広告が開始された」フラグを立てます。
LoadAdsIfNullの中身
LoadAdsIfNullの中身は以下のとおりです。広告がnullだったらロードするようにしています。
static void LoadAdsIfNull()
{
if (BannerManager.Ad == null) BannerManager.Instance.LoadAd();
}
なお、ややこしい話ですが、バナー広告はロードすると勝手に自動で表示されます。インタースティシャルなど他の広告はロードしても勝手には表示はされません。バナー広告だけ扱いが違いますので注意してください。
インターネットの接続確認
インターネット接続を確認するクラスについてはkanのメモ帳様の記事を参考に作成しました(kanのメモ帳様の記事)。前回の記事のTryAdMob_Eventの「1.インターネット接続確認」のInternetCheckerがそのクラスです。静的クラスにしています。中身は次のとおりです。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
/// <summary>
/// インターネットに接続されているか確認するクラス
/// </summary>
public static class InternetChecker
{
//接続確認用URL
private static readonly List<string> Urls = new ()
{
"https://mochitchies.com/", //あなた自身のURLに変更してください
"https://b.hatena.ne.jp/mochitchies/", //あなた自身のURLに変更してください
"https://note.com/mochitchies", //あなた自身のURLに変更してください
};
public static IEnumerator Check(Action<bool> callback, int timeOut = 2)
{
if (Application.internetReachability == NetworkReachability.NotReachable)
{
Debug.Log("Internet not reachable");
callback(false);
yield break;
}
bool result = false;
for (int i = 0; i < Urls.Count; i++)
{
using var request = new UnityWebRequest(Urls[i]) { timeout = timeOut };
yield return request.SendWebRequest();
if (request.result != UnityWebRequest.Result.Success)
{
Debug.Log($"Internet ng :{Urls[i]} : result {request.result} : error {request.error}");
}
else
{
Debug.Log($"Internet OK : {Urls[i]}");
result = true;
break;
}
}
callback(result);
}
}
コードを上から順に解説します。UrlsはstringのListで、インターネット接続確認を行うためのURLをstringとして持っています。
その下のCheckが、接続の確認処理を行うメソッドです。Checkの第一引数はboolを引数に持つデリゲートで、第二引数がタイムアウトを設定するためのintです。Checkはコルーチンなので戻り値が取れませんので、デリゲートを通じて最終結果をメソッド外に渡すということをやっています。第二引数のint timeOut = 2は、第二引数が指定されなかった場合に2が初期値として与えられるという意味です。
Checkメソッドの冒頭で、Application.internetReachabilityでネットの接続設定状態を確認しています。ネットの接続設定がOFFならば、callbackにfalseを渡して実行してCheckメソッドを抜けます。
for文の中の説明をします。for文の中で、Urlsの小さいインデックスの要素から順に接続確認していきます。そして、接続確認が取れた時点で、それ以降の確認は無駄なので、すぐにfor文を抜けるようにしています。HTTPのリクエストが以下のコードです。timeoutプロパティには特に指定がなければ、初期値の2(秒)が代入されるようにしています。
using var request = new UnityWebRequest(Urls[i]) { timeout = timeOut };
そして、リクエストの送信が以下のコードです。request.SendWebRequestはコルーチンですので、この処理が完了するまで待機する形となります。
yield return request.SendWebRequest();
request.SendWebRequestの処理完了後に行う分岐処理が以下のコードです。request.resultがUnityWebRequest.Result.Successでない場合は通信失敗です。なので、失敗の場合は、次のURLのチェックに移行します。全てのURLに対して通信が失敗した場合は、result = falseが確定し、「ネット接続なし」が確定することになります。request.resultがUnityWebRequest.Result.Successの場合はresult = trueが確定し、「ネット接続あり」が確定することになります。
if (request.result != UnityWebRequest.Result.Success)
{
Debug.Log($"Internet ng :{Urls[i]} : result {request.result} : error {request.error}");
}
else
{
Debug.Log($"Internet OK : {Urls[i]}");
result = true;
break;
}
修正したインターネット接続確認クラス
2025年4月26日に追記しています。前項のインターネット接続確認クラスを修正したクラスを作成しました。修正点は以下の通りです。
- Checkメソッドを連続実行した場合はキャッシュを返すようにした
- GETメソッドよりも軽いHEADメソッドを使うようにした
Checkメソッドを間違って連続実行しても、5秒以内であれば前回の結果を返すようにしました。一度に大量のリクエストを投げたらサーバーに負荷がかかりますので、その防止のためです。
また、GETメソッドではなくHEADメソッドを使うように変更しました。リクエスト1回あたりのサーバー負荷を下げるためです。
アプリがヒットしたらサーバーに大量のリクエストが投げられことになりますので、今のうちから対処しましょう。
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
/// <summary>
/// インターネットに接続されているか確認するクラス
/// </summary>
public static class InternetChecker2
{
private static bool? IsInternetAvailable;
private static float LastTime;
private static float CACHE_DURATION = 5f; // キャッシュの有効期限(秒)
//接続確認用URL
private static readonly List<string> Urls = new ()
{
"https://mochitchies.com/", //あなた自身のURLに変更してください
"https://b.hatena.ne.jp/mochitchies/", //あなた自身のURLに変更してください
"https://note.com/mochitchies", //あなた自身のURLに変更してください
};
public static IEnumerator Check(Action<bool> callback, int timeOut = 5)
{
// キャッシュが有効で、有効期限内であればキャッシュを返す
if (IsInternetAvailable.HasValue && Time.time - LastTime < CACHE_DURATION)
{
Debug.Log($"Internet cache={IsInternetAvailable.Value}");
callback(IsInternetAvailable.Value);
yield break;
}
if (Application.internetReachability == NetworkReachability.NotReachable)
{
Debug.Log("Internet not reachable");
callback(false);
yield break;
}
bool result = false;
for (int i = 0; i < Urls.Count; ++i)
{
using (UnityWebRequest request = UnityWebRequest.Head(Urls[i]))// HEADリクエストを使用
{
request.timeout = timeOut;
yield return request.SendWebRequest();
var b = request.result == UnityWebRequest.Result.Success && request.responseCode == 200;
if (b)
{
result = true;
break;
}
}
}
IsInternetAvailable = result;
LastTime = Time.time;
Debug.Log($"Internet result={result}");
callback(result);
}
}
コードの全体
AdMobManagerクラスのコードの全体は以下の通りです。
using System;
using System.Collections;
using UnityEngine;
using GoogleMobileAds.Api;
using GoogleMobileAds.Ump.Api;
public class AdMobManager : MonoBehaviour
{
public static AdMobManager Instance;
public const string DRO_BANNER = "ca-app-pub-3940256099942544/6300978111";// デモ広告ユニットID
static bool Ad_Already_Started = false;
void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
IEnumerator Start()
{
MobileAdsEventExecutor.Initialize(); // コールバック関数からメインスレッドを利用できるようにする
ConsentInformation.Reset(); //テスト用
while (BannerManager.Instance == null) yield return null;
TryAdMob();
yield return null;
yield break;
}
public static void TryAdMob()
{
if (TryAdMob_Busy || Ad_Already_Started) return;
TryAdMob_Busy = true;
Instance.StartCoroutine(TryAdMob_Event());
}
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); // デバッグの同意フォームは英語じゃないとエラーが返る
if (canShowAd == true)
{
while (!ConsentInformation.CanRequestAds()) yield return null; // 広告可能になるまで待つ
yield return AdFinalize(); // 広告を開始する
}
Debug.Log($"TryAdMob FinalResult={canShowAd}");
TryAdMob_Busy = false;
}
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);
}
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);
}
}
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",
};
static IEnumerator AdFinalize()
{
// すべての広告に使用されるグローバル設定=======================
var request = new RequestConfiguration()
{
TagForChildDirectedTreatment = TagForChildDirectedTreatment.False,
MaxAdContentRating = MaxAdContentRating.T,
};
MobileAds.SetRequestConfiguration(request);
MobileAds.SetiOSAppPauseOnBackground(true);//iOSでフルスクリーン広告が表示されている間、Unityアプリを一時停止
// 広告の初期化===========================================
bool? result = null;
MobileAds.Initialize(initstatus =>
{
result = initstatus != null; // nullでなければ合格
});
while (result == null) yield return null;//結果を待つ
// 広告のロード===========================================
if (result == true)
{
Ad_Already_Started = true; //広告表示に関係するのでこの位置
LoadAdsIfNull();
}
}
static void LoadAdsIfNull()
{
if (BannerManager.Ad == null) BannerManager.Instance.LoadAd();
}
}
動作確認して見よう
Hierarchyには以下のように、AdMobManagerとBannerManagerのGameObjectが配置されていますか?

クラスファイルは以下のようになっていますか?AdMobManagerクラスはAdMobManagerのGameObjectに、BannerManagerクラスはBannerManagerのGameObjectにコンポーネントとしてアタッチされていますか?

では、Unityのプレイボタンを押して動作確認して見ましょう。Unity上で動作確認するだけならば、Google Mobile Ads SettingsのGoogle Mobile Ads App IDは空でも大丈夫です。以下のようなGDPR同意フォームが表示されたら成功です😆💯。

終わりに
今回までの記事で、GDPR同意取得が取り敢えず行えるようになりました。いや、長かったですね。お疲れ様です。次回ですが、GDPRの規則では同意後の取消が必須ですので、その対応方法について説明します。また、iOSのATT(=App Tracking Transparency)への対応についても説明します。
このシリーズの記事
- その1(GDPRの概要)
- その2(AdMob 全体を管理するクラスのコード)
- その3(バナーを表示するクラスのコード)
- その4(GDPR同意取得の詳細フロー)
- その5(GDPR同意取得メソッドのコード)
- その6(GDPR同意取得メソッドのコードの補足)
- その7:最終回(GDPR同意取り消しフォームやATT対応について)
いつも記事をお読みいただきありがとうございます!
内容が役立った、応援したいと思っていただけた方は、サーバー代や活動費としてサポート(投げ銭・150円〜)をいただけると励みになります。
※いただいたサポート(投げ銭)の原則としての返金には対応いたしかねます。あらかじめご了承のうえ、温かいご支援をお願いいたします。

コメント