ロバメモ - 素人のUnity覚書と奮闘記

素人のUnity覚書と奮闘記

リワード広告を使ってみた

UnityでAdmobのリワード広告を使ってみたので方法と注意点をメモ。

導入方法

リワード広告  |  Unity  |  Google Developers
概ね、公式通りでできた。
環境:Unity2019.3.0f5 / Mac

コード

using UnityEngine;
using UnityEngine.UI;
using GoogleMobileAds.Api;
using System;

public class AdMobReward : MonoBehaviour
{
    //広告ユニットID
    string adUnitId;

    //リワード広告のオブジェクト
    RewardedAd rewardedAd;

    void Start()
    {
        //UnitID設定
        if (Debug.isDebugBuild)
        {
            adUnitId = "ca-app-pub-3940256099942544/5224354917"; //テスト用
        }
        else
        {
            adUnitId = "本番用の広告ユニットID";
        }

        //リワード広告オブジェクトの作成
        rewardedAd = new RewardedAd(adUnitId);

        //イベントハンドラの登録
        rewardedAd.OnUserEarnedReward += HandleUserEarnedReward;
        rewardedAd.OnAdClosed += HandleRewardedAdClosed;

        //リクエスト
        RequestLoad();

    }


    //リクエストと読み込み
    void RequestLoad()
    {
        AdRequest request = new AdRequest.Builder().AddTestDevice("デバイスID").Build();
        rewardedAd.LoadAd(request);
    }

    //表示(再生ボタンのメソッド)
    public void Show()
    {
        if (rewardedAd.IsLoaded())
        {
            rewardedAd.Show();
        }
    }

    //報酬受け取り時のイベントハンドラ
    bool isReward;
    public void HandleUserEarnedReward(object sender, Reward args)
    {
        isReward = true;
    }

    //広告を閉じた時のイベントハンドラ
    bool isClose;
    public void HandleRewardedAdClosed(object sender, EventArgs args)
    {
        isClose = true;
    }

    //広告とUnityではスレッドが違うようなので、bool値で判定してUnity側で処理を実行するための処置
    void Update()
    {
        if (isClose)
        {
            if (isReward)
            {
                //報酬受け取りの処理
                GoldManager.instance.addGold(price);
            }
            //広告を閉じた時の処理
            gameObject.SetActive(false);
        }
    }
}

遭遇したエラーと対処法

//報酬受け取り時のイベントハンドラ
bool isReward;
public void HandleUserEarnedReward(object sender, Reward args)
{
    GoldManager.instance.addGold(price);
    isReward = true;
}

当初、上記のように報酬を受け取る時のイベントハンドラGoldManager.instance.addGold(price);を書いていたんだけど、実機でテストするとこの部分でエラーが出て、報酬は加算されるんだけどそれ以降の処理が実行されない(isRewardがfalseのまま)という不具合にあった。

エラー内容

AndroidPlayer(XXXXX) UnityException: TrySetFloat can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
TrySetFloatは、メインスレッドからのみ呼び出すことができます。
コンストラクターとフィールド初期化子は、シーンの読み込み時に読み込みスレッドから実行されます。
コンストラクターまたはフィールド初期化子でこの関数を使用せず、代わりに初期化コードをAwakeまたはStart関数に移動します。

原因

調べてみると、Unityはメインスレッドで実行されるけど、広告は別のスレッドで実行されているらしく、広告側からメインのスレッドで定義されてるメソッドを使おうとしたから(?)あかんよ〜ってことみたい。

参照: [Admob + PlayerPrefs] => TrySetInt can only be called from the main thread - Unity Answers

対処法

上記参照記事によると、bool値は使えるようなので、イベントハンドラが実行されたらtrueにして、Updateで監視するようにした。

テスト広告についての問題点 〜保留中〜

//UnitID設定
if (Debug.isDebugBuild)
{
    adUnitId = "ca-app-pub-3940256099942544/5224354917"; //テスト用
}
else
{
    adUnitId = "本番用の広告ユニットID";
}

こんな感じで、Development Buildにチェックいれてビルドしたらテスト用の広告が流れるようにしたので、デバッグの時は問題なかった。
本番用でビルドしたとき、テストデバイスでもテスト用の広告を流したいので、次のように書いたけどテスト用の広告になってないっぽい。普通の広告が再生された。
不正カウントされたら困るからテストできないし、調べても出てこなくて保留中。困った。

AdRequest request = new AdRequest.Builder().AddTestDevice("デバイスID").Build();

ちなみに、デバイスIDはデバイスIDを調べるアプリをスマホに入れて調べた値なので、間違いはないと思う。

以上。