概要
初めてUnityにAdMobを導入した際にハマったことのまとめです。
今回はリワード広告を使い、動作確認したところRewardedAd
にセットしたOnAdFailedToLoad
(広告の読み込みに失敗したときに呼び出されるメソッド)にしかならず、ググってもなかなか原因がわからないまま数日を無駄にした感じです笑汗
先にネタばらしすると、サンプル広告(デバッグ用の広告)を使って動作確認していて、テストデバイスの登録が必要で登録のし忘れによることが原因でした。
ちゃんと公式を呼ばずにサンプル広告ユニットIDだけセットして動作確認していたので、改めてドキュメントとかマニュアルは全部確認してからやらないとなと反省です笑汗
前提
すでにUnityにAdMobを入れて作業している前提で話をまとめていくので、まだ導入前の場合は公式のセットアップと参考にしていた次の記事を共有しておきます。
やっていたこと
簡単にスクリプトを解説します。
上記の記事や他の記事を参考に作っているので、設定中の方は参考になればなと。
まず、広告IDなどは次のように設定します。
DEVELOPMENT_BUILD
の中にセットしている広告IDがサンプルで公式ページに載っているやつです。
namespace Google
{
namespace Mobile
{
namespace Ads
{
public class Common
{
# if DEVELOPMENT_BUILD
# if UNITY_EDITOR
public static readonly string APP_ID = "-1";
public static readonly string AD_REWARD_UNIT_ID = "-1";
# elif UNITY_ANDROID
public static readonly string APP_ID = "ca-app-pub-3940256099942544~3347511713";
public static readonly string AD_REWARD_UNIT_ID = "ca-app-pub-3940256099942544/5224354917";
# elif UNITY_IOS
public static readonly string APP_ID = "ca-app-pub-3940256099942544~3347511713";
public static readonly string AD_REWARD_UNIT_ID = "ca-app-pub-3940256099942544/1712485313";
# endif
# else
# if UNITY_EDITOR
public static readonly string APP_ID = "-1";
public static readonly string AD_REWARD_UNIT_ID = "-1";
# elif UNITY_ANDROID
public static readonly string APP_ID = "ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy";
public static readonly string AD_REWARD_UNIT_ID = "ca-app-pub-xxxxxxxxxxxxxxxx/aaaaaaaaaa";
# elif UNITY_IOS
public static readonly string APP_ID = "ca-app-pub-xxxxxxxxxxxxxxxx~zzzzzzzzzz";
public static readonly string AD_REWARD_UNIT_ID = "ca-app-pub-xxxxxxxxxxxxxxxx/iiiiiiiiii";
# endif
# endif
}
}
}
}
次にリワードに関する処理のスクリプトです。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GoogleMobileAds.Api;
using GoogleMobileAds.Common;
using System;
namespace Google
{
namespace Mobile
{
namespace Ads
{
public class Reward : MonoBehaviour
{
RewardedAd rewarded;
public bool IsLoaded { get { return rewarded.IsLoaded(); } }
public delegate void RewardHundler(bool result, string response);
RewardHundler _callback;
public void CreateAndLoadRewardedAd(RewardHundler callback)
{
_callback = callback;
rewarded = new RewardedAd(Common.AD_REWARD_UNIT_ID);
rewarded.OnAdLoaded += HandleRewardedAdLoaded;
rewarded.OnAdFailedToLoad += HandleRewardedAdFailedToLoad;
rewarded.OnAdFailedToShow += HandleRewardedAdFailedToShow;
rewarded.OnUserEarnedReward += HandleUserEarnedReward;
rewarded.OnAdOpening += HandleRewardedAdOpening;
rewarded.OnAdClosed += HandleRewardedAdClosed;
AdRequest request = new AdRequest.Builder().Build();
rewarded.LoadAd(request);
}
public void UserChoseToWatchAd()
{
if (rewarded.IsLoaded())
rewarded.Show();
}
private void HandleRewardedAdLoaded(object sender, EventArgs args)
{
Debug.Log("HandleRewardedAdLoaded event received");
}
private void HandleRewardedAdFailedToLoad(object sender, AdFailedToLoadEventArgs args)
{
Debug.Log("HandleRewardedAdFailedToLoad event received with message: " + args.ToString());
if (_callback == null)
return;
Debug.Log("HandleRewardedAdFailedToLoad callback.");
_callback(false, args.ToString());
}
private void HandleRewardedAdFailedToShow(object sender, AdErrorEventArgs args)
{
Debug.Log("HandleRewardedAdFailedToShow event received with message: " + args.Message);
if (_callback == null)
return;
Debug.Log("HandleRewardedAdFailedToShow callback.");
_callback(false, args.ToString());
}
private void HandleRewardedAdClosed(object sender, EventArgs args)
{
Debug.Log("HandleRewardedAdClosed event received");
if (_callback == null)
return;
Debug.Log("HandleRewardedAdClosed callback.");
_callback(true, args.ToString());
}
private void HandleRewardedAdOpening(object sender, EventArgs args)
{
Debug.Log("HandleRewardedAdOpening event received");
// TODO: 必要に応じて制御を追記
}
private void HandleUserEarnedReward(object sender, GoogleMobileAds.Api.Reward args)
{
Debug.Log("HandleRewardedAdRewarded event received for " + args.Amount.ToString() + " " + args.Type);
// TODO: 必要に応じて制御を追記
}
}
}
}
}
最後に初期化やリワードを開始するスクリプトです。
using UnityEngine;
using UnityEngine.SceneManagement;
public class StartButton : MonoBehaviour
{
[SerializeField]
Google.Mobile.Ads.Reward _reward;
[SerializeField]
AudioSource _audio;
void Start()
{
// リワード 初期化
_reward.CreateAndLoadRewardedAd((result, response) =>
{
Debug.Log("reward.callback response: " + response);
if (result)
SceneManager.LoadScene("NextScene");
});
}
public void OnClickStartButton()
{
_audio.Play();
if (_reward.IsLoaded)
// リワード 開始
_reward.UserChoseToWatchAd();
}
}
動作確認
ちなみにAdMobの動作確認は実施でしかできないと勝手に思っていたんですが、実際にUnity上で動かしてみたところAdMobがUnityエディタ用に広告動作を用意していたので、エディタでエラーが出ないことを確認してから実機確認に入ると作業しやすいかと。
ハマった内容
最後の方に出ているログを見ると次の内容でXcode上でエラーになりました。
HandleRewardedAdFailedToLoad event received with message: GoogleMobileAds.Api.AdFailedToLoadEventArgs
Google.Mobile.Ads.Reward:HandleRewardedAdFailedToLoad(Object, AdFailedToLoadEventArgs)
System.EventHandler`1:Invoke(Object, TEventArgs)
System.EventHandler`1:Invoke(Object, TEventArgs)
HandleRewardedAdFailedToLoad callback.
Google.Mobile.Ads.Reward:HandleRewardedAdFailedToLoad(Object, AdFailedToLoadEventArgs)
System.EventHandler`1:Invoke(Object, TEventArgs)
System.EventHandler`1:Invoke(Object, TEventArgs)
libc++abi: terminating with uncaught exception of type Il2CppExceptionWrapper
terminating with uncaught exception of type Il2CppExceptionWrapper
(lldb)
一番下のlibc++abi
らへんでググってもHandleRewardedAdFailedToLoad
をセットしているOnAdFailedToLoad
に関してググっても原因はわからない状況でした。
上記のスクリプトは最終的な完成形のもので、このログが出てエラーになってアプリがクラッシュしていたときはもう少し違って幾つか修正した点がありました。
そのスクリプトを修正してもアプリのクラッシュは解決したもののOnAdFailedToLoad
が呼ばれて広告の読み込みに失敗する点はどうしても変わらなかったので、再度公式を読み返したところでテストデバイスの未登録に気づきました笑汗
テストデバイスの登録
公式のAdMob 管理画面でテストデバイスを追加するからスタートガイドのテストデバイスを設定するからテストデバイスの設定方法を確認していきます。



IDFA
iOSの場合、(2021年9月現在)IDFA(Identification For Advertisers)の取得が難しく次の方法から取得するしかありません。
- Swiftの
ASIdentifierManager
を使ってスクリプトで取得する。 - IDFAを取得して表示してくれるアプリをインストールする。
セキュリティを考えるならスクリプトで自前でIDFAを取得した方がいいんですが、面倒だったんで仕事でも使ったことがあるAdjustのアプリでIDFAを取得することにしました。
取得した後はもう使わないので、アプリを削除するか設定 > プライバシー > トラッキングからAdjustのトラッキングをdisableにしておくとよいかと。

まとめ
今回は先にiOSを対応していたので、次にAndroidを対応してまた何かハマったらアプデするか新しい記事でまとめようと思います。