そういうのがいいブログ

アプリ個人開発 まるブログ

アプリ開発覚え書き

【Unity】GDPR対応 UMPを使用し同意フォームを表示する方法 Android iOS

仕様

Unityバージョン:2021.3.27f1
GoogleMobileAds-v8.5.3

前提

・GoogleMobileAdsをプロジェクトに導入済みであること
・広告が表示できる状態であること

はじめに

AdMobの管理画面にこんなメッセージが出てきました。

欧州にもアプリを出していきたいのでGDPR対応をしていきます。
GDPRについての説明は省略します。

警告文にいろいろ書いてありますが
どこかの会社の同意管理プラットフォームと契約してユーザーの同意を得るか
Googleが用意した同意管理の様式でユーザーの同意を得るかという理解をしました。

下記の文にあるUMP(User Messaging Platform) SDK
使用して対応していけばよさそうです。
このUMP SDKはGoogleMobileAdsに含まれています。

Google の同意管理ソリューションに関心をお持ちの場合は、まず GDPR メッセージを設定し、 UMP SDK を実装してください


User Messaging Platform(UMP)SDK設定のページはこちら

https://developers.google.com/admob/unity/privacy?hl=jadevelopers.google.com

注)法律の専門家ではありませんので自己責任にて欧州へのアプリリリースをお願いします。

手順1. 同意依頼メッセージの作成

→AdMob管理画面の「プライバシーとメッセージ」


GDPRの歯車をクリック


→メッセージ
GDPRメッセージを作成


以下の画面になるので各項目を入力します。


アプリの選択の他は以下のように設定しました。


次に進むとユーザーに表示する同意画面のプレビューになります。
以下の設定にして公開しました。
アプリ:対象のアプリが選択されていることを確認
言語:デフォルトの言語は英語に設定
別の言語:すべての言語にチェック

手順2.アプリ計測の遅延設定

ここからUnity上での設定になります。

ユーザーの同意が得られるまでユーザーの計測ができないため
Mobile Ads SDK を初期化するか広告を読み込むまで、
アプリの測定を明示的に遅らせる必要があります。

設定は簡単で以下の手順で設定ウインドウ表示してから
→アセット
Google Mobile Ads]
→Settings


同意メッセージのDelay app measurementを有効にします。

手順3.デバイスIDの取得

テストで同意フォームを表示するためには、
手持ちの端末が欧州経済領域(EEA)に存在していると設定する必要があります。
その設定のためには、デバイスのIDが必要ですので最初にデバイスIDを取得してしまいます。
(ここでいうデバイスIDは広告のテストデバイスIDとはまた別の文字列になります。)


端末側での関数の実行結果を確認する必要があるため
下記のコードをアプリ側で実行してください。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GDPR : MonoBehaviour
{
    void Start()
    {
        //デバッグ用に端末のID取得
        //================================================================
        // 端末固有のIDを取得
        string deviceID = SystemInfo.deviceUniqueIdentifier;

        // 取得したIDを全て大文字に変換(大文字にしないとデバッグができません)
        string deviceIDUpperCase = deviceID.ToUpper();

        // 端末IDの表示
        Debug.Log("TestDeviceHashedId = " + deviceIDUpperCase);
        //================================================================
    }

}


iOSではXcodeから実機テストすると実機ログを確認できます。
例:4C70843B-1592-427A-831F-D72A3298AD5D


Androidではログ確認はできないため、Android Logcatを導入し確認可能にします。
(パッケージを入れるだけなのでとても簡単です。)
marumaro7.hatenablog.com

Android Logcatの検索窓に
TestDeviceHashedId
と打ち込むとデバイスIDが表示されるはずです。
例:F8026D2238D034DD0896BF099FAAD9CC
取得したデバイスIDはメモしておいてください。

手順4.スクリプト作成

スクリプトは次の3ステップで完成となります。
1.基本スクリプトの作成
2.デバイスIDの設定
3.広告読み込みの設定

4-1.基本スクリプトの作成

以下のスクリプトを作成し、空のゲームオブジェクトに割り当てます。
スクリプトの詳しい内容はコメントをご確認ください。

using System.Collections;
using System.Collections.Generic;
using GoogleMobileAds.Api;
using GoogleMobileAds.Ump.Api;
using UnityEngine;

public class GDPR : MonoBehaviour
{
    //広告読み込み開始用
    //広告のスクリプトをインスペクター上でそれぞれ割り付けてください
    //以下は例です。
    //==============================================================
    [SerializeField] private AdMobBanner adMobBanner;
    [SerializeField] private AdMobInterstitial adMobInterstitial;
    [SerializeField] private AdMobReward adMobReward;
    //==============================================================

    private void Start()
    {
        //デバッグ用に端末のID取得
        //================================================================
        // 端末固有のIDを取得
        string deviceID = SystemInfo.deviceUniqueIdentifier;

        // 取得したIDを全て大文字に変換(大文字で登録しないと同意フォームが表示されませんでした)
        string deviceIDUpperCase = deviceID.ToUpper();

        // 端末IDの表示
        Debug.Log("TestDeviceHashedId = " + deviceIDUpperCase);
        //================================================================


        //同意フォームのリクエスト作成
        ConsentRequestParameters request = new ConsentRequestParameters
        {
            // 未成年者の同意に関するタグを設定します。
            // falseはユーザーが未成年者でないことを意味します。
            TagForUnderAgeOfConsent = false,


            //同意フォームテスト用
            //==========================================================================
            //GDPRの対象地域で起動したことにする設定            
            ConsentDebugSettings = new ConsentDebugSettings
            {
                DebugGeography = DebugGeography.EEA,
                TestDeviceHashedIds = new List<string>
                {
                    //同意フォームを表示する端末のデバイスIDを入力
                    //Android 例
                    "F8026D2238D034DD0896BF099FAAD9CC",                    
                    
                    //iOS 例
                    "4C70843B-1592-427A-831F-D72A3298AD5D"
                }
            }
            //==========================================================================            
        };

        // 同意情報の更新をリクエスト
        ConsentInformation.Update(request, OnConsentInfoUpdated);        
    }

    //同意情報の更新後に実行する関数
    private void OnConsentInfoUpdated(FormError consentError)
    {
        if (consentError != null)
        {
            Debug.Log("error consentError = " + consentError);
            return;
        }

        //ユーザーの同意が必要でまだ得られていない場合に、同意フォームをロードして表示します。
        ConsentForm.LoadAndShowConsentFormIfRequired((FormError formError) =>
        {
            //同意が得られなかった時の処理
            if (formError != null)
            {
                Debug.Log("error consentError = " + consentError);
                return;
            }


            //同意ステータス確認
            //https://developers.google.com/admob/unity/reference/namespace/google-mobile-ads/ump/api#namespace_google_mobile_ads_1_1_ump_1_1_api_1aa83ad2ecf6f2a08c584b60cef06f5133
            //NotRequired:同意は必要ありません。CanRequestAds()はtrueとなります。
            //Obtained:ユーザーの同意が得られました。パーソナライズされたものとパーソナライズされていないものは未定義です。
            //Required:ユーザーの同意が必要ですが、まだ取得されていません。
            //Unknown:不明な同意状況。同意状況が確認とれるまではUnkownが表示されます。
            Debug.Log("ConsentStatus = " + ConsentInformation.ConsentStatus.ToString());

            //CanRequestAds()の値確認用
            Debug.Log("CanRequestAds = " + ConsentInformation.CanRequestAds());

            // ここまで処理が進んでいれば同意が得られたことになる
            if (ConsentInformation.CanRequestAds())
            {
                //https://developers.google.com/admob/unity/quick-start?hl=ja
                // true の場合、GoogleMobileAds によって発生するすべてのイベントが発生します
                // Unity メインスレッド上で。 デフォルト値は false です。
                MobileAds.RaiseAdEventsOnUnityMainThread = true;
                 
                //広告の初期化完了後 広告読み込み開始
                MobileAds.Initialize((InitializationStatus initstatus) =>
                {
                    //広告のスクリプト側で設定している広告を読み込む関数をここで実行してください。
                    //広告読み込み開始
                    //以下は例です。
                    //===========================
                    adMobBanner.AdStart();
                    adMobInterstitial.AdStart();
                    adMobReward.AdStart();
                    //===========================
                });
                
            }
        });
    }



    //同意フォームの再表示用
    public void LoadAndShowConsentForm()
    {
        Debug.Log("LoadAndShowConsentForm Start!");

        // 同意フォームをロードします
        ConsentForm.Load((consentForm, loadError) =>
        {
            if (loadError != null)
            {
                Debug.Log("error loadError = " + loadError);
                return;
            }

            // 同意フォームがロードされました
            // フォームを表示します
            consentForm.Show(showError =>
            {
                if (showError != null)
                {
                    Debug.Log("error showError = " + showError);
                    return;
                }
            });
        });
    }


    //GDPRデバッグテスト用 同意情報リセット
    public void GDPRReset()
    {
        Debug.Log("Reset Start!");
        ConsentInformation.Reset();
    }


}



以下、同意フォーム再表示用のLoadAndShowConsentForm()関数と、
同意情報リセットGDPRReset()関数はテストを円滑に実施するために書いています。
不要であれば削除していただいて問題ありません。

同意フォーム再表示用 LoadAndShowConsentForm()関数

    //同意フォームの再表示用
    public void LoadAndShowConsentForm()
    {
        Debug.Log("LoadAndShowConsentForm Start!");

        // 同意フォームをロードします
        ConsentForm.Load((consentForm, loadError) =>
        {
            if (loadError != null)
            {
                Debug.Log("error loadError = " + loadError);
                return;
            }

            // 同意フォームがロードされました
            // フォームを表示します
            consentForm.Show(showError =>
            {
                if (showError != null)
                {
                    Debug.Log("error showError = " + showError);
                    return;
                }
            });
        });
    }


同意情報リセット GDPRReset()関数

    //GDPRデバッグテスト用 同意情報リセット
    public void GDPRReset()
    {
        Debug.Log("Reset Start!");
        ConsentInformation.Reset();
    }

4-2.デバイスIDの設定

下記の部分のデバイスIDを先ほど取得したデバイスIDに差し替えてください。

            //同意フォームテスト用
            //==========================================================================
            //GDPRの対象地域で起動したことにする設定            
            ConsentDebugSettings = new ConsentDebugSettings
            {
                DebugGeography = DebugGeography.EEA,
                TestDeviceHashedIds = new List<string>
                {
                    //同意フォームを表示する端末のデバイスIDを入力
                    //Android 例
                    "F8026D2238D034DD0896BF099FAAD9CC",                    
                    
                    //iOS 例
                    "4C70843B-1592-427A-831F-D72A3298AD5D"
                }
            }
            //========================================================================== 

4-3.広告読み込みの設定

以下の2箇所は私が使用している広告スクリプト名、関数名のため
エラーが発生していると思います。
ご自身のプロジェクトで使用される広告読み込み関数に差し替えてください。

    //広告読み込み開始用
    //広告のスクリプトをインスペクター上でそれぞれ割り付けてください
    //以下は例です。
    //==============================================================
    [SerializeField] private AdMobBanner adMobBanner;
    [SerializeField] private AdMobInterstitial adMobInterstitial;
    [SerializeField] private AdMobReward adMobReward;
    //==============================================================
                //広告の初期化完了後 広告読み込み開始
                MobileAds.Initialize((InitializationStatus initstatus) =>
                {
                    //広告のスクリプト側で設定している広告を読み込む関数をここで実行してください。
                    //広告読み込み開始
                    //以下は例です。
                    //===========================
                    adMobBanner.AdStart();
                    adMobInterstitial.AdStart();
                    adMobReward.AdStart();
                    //===========================
                });

実機確認

実機で起動すると以下のウインドウが表示されるはずです。
※正しいデバイスIDが登録されていないと表示されません。

実装方法は以上です。

広告表示の確認

ここからは同意フォームの入力結果による広告表示のメモとなります。(Android端末で実施)

・「同意」ボタン押下後
問題なし 広告表示される


・「オプションを管理」→「すべて承認」押下後
問題なし 広告表示される

 → 


・「オプションを管理」→「選択を確定」押下後
問題あり 広告が表示されない(詳細設定の内容全てを有効にしても表示されない)

 → 


・「オプションを管理」→「選択を確定」押下後 → フォームを再表示して同意
難あり 再起動すると広告が表示される

詳細
1.「オプションを管理」→「選択を確定」押下後 広告が表示されない状態から
 →   

2.同意フォームを再表示して同意
この状態で同意しても広告は表示されないがアプリを再起動すると広告は表示される


結論、「オプションを管理」→「選択を確定」と押された場合広告が表示されなくなります。
UMP SDKが用意してくれた広告表示可否を判断するための
ConsentInformation.CanRequestAds()
の値はtrueであるためUMP SDKとしては広告が出せると判定されているが
実際は広告を出せないということになります。


これは下記でで2020年から議論されているようですが未だ解決していません。
(Safariで開くとメッセージが省略されるため、
 それぞれのスレッドをクリックして展開する必要があります。)
groups.google.com



それで、どうする??
についてですが、現在、対処法は確定していません。
テストしていったところ、同意状態を示すConsentStatusがObtained(同意)
となった時が同意フォームが表示され、いずれかのボタンが押されたということになるため、

「ConsentStatusがObtained(同意)」かつ「広告のロードが失敗する」

この2つの条件が揃った場合に以下のようなテキストを表示して
同意フォームの同意を促すしかないのかなと考えています。
「同意フォームの同意がなければ広告が発生せず報酬の受け取りができません。
 次のフォームに同意してアプリを再起動してください」


ちなみに、
日本にいてデバイスIDを設定していない時はEEA対象外の地域となるため
同意フォームは表示されずに広告の読み込みは開始されます。
※同意状態を示すConsentStatusはNotRequired(同意の必要なし)となります。

おわりに

広告が出ない状況に対しての最適解がない状態ですが
同意フォームを表示する目的は果たせたので一歩前進です。

残りの未確定ポイントは、iOSのATTリクエストウインドウは
GDPR同意フォームの後に表示することで問題ないのかという点です。

こちらはiOSの審査に出すまでわからないため広告表示問題と併せて
情報がありましたら教えていただけると嬉しいです。

本記事からなにか得るものがありましたら幸いです。ではでは。

プログラム入門本 書きました

marumaro7.hatenablog.com

参考

・参考動画

www.youtube.com


・リファレンス

developers.google.com

developers.google.com


・確認した情報 www.reddit.com

Androidパーソナライズされていない広告を出す方法らしい itnext.io