UnityでAdmobをアプデート（インポート）する方法(iOS14対応)

#UnityでAdmob広告をアップデートする
###Admobページに悲報
Unityで作成したスマホアプリにAdmob広告を付けていたのですが、ある日Admobのマイページを開くとこのような表示が。。。
血の気が引く。。。

 ![スクリーンショット 2021-03-10 22.50.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239793/481a70e6-9507-31bd-15e0-88e673cac383.png)

思えば以前から警告のメールが来ていたような気もするが、作り直すのがめんどかったので無視していたらいよいよ赤札が貼られてしまった。
内容はiOS14対応しないと広告表示されませんぜ、的な感じのやつ。

Admobのバージョンを上げたりATTを導入したりする必要があるようなので、一通りの手順をメモ書き程度に残しておく。
※あくまでも自分が設定した内容をまとめています


###最新版のAdmobプラグインをダウンロード
現在(2021/03/10)の最新バージョンのプラグインをダウンロードする。
https://github.com/googleads/googleads-mobile-unity/releases/tag/v5.4.0

[Add support for iOS14 with Google's SKAdNetwork identifiers automatically included in
Info.plist.]
必要な設定をInfo.plistに含んでくれるっぽい。ありがたい。


###Unityにダウンロードしたパッケージを追加
[Assets]-[ImportPackage]-[CustomPackage...]
をクリックし、先ほどダウンロードした「GoogleMobileAds-v5.4.0.unitypackage」ファイルをインポートする。
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3233393739332f37643634663363642d623463662d306666632d633763332d3630623663643133323238642e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239793/d408295c-4a28-4e10-bc09-28fe839ff28a.png)

↓するとこんな表示が出るためそのままImport
![GMA.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239793/f4500b02-a60b-4169-6b56-33bf9cf088f6.png)


Import完了！
UnityのProjectに↓こんなのが追加される。
![スクリーンショット 2021-03-10 23.11.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239793/13a64ac2-3790-f6f2-ec24-05e81c68d6d7.png)


###GoogleMobileAdsの設定
UnityのProjectで右クリックをし、以下から設定画面を開く。
![GMASetting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239793/11ccbf27-e325-2ae0-902c-954417fb8884.png)



設定画面にiOS,Androidの各アプリIDを入力
![スクリーンショット 2021-03-10 23.19.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239793/43f4980b-71f2-6925-4d58-c4f24c1cb796.png)


###ATT対応
これまでの設定でGoogle Mobile Ads SDKを最新のバージョン（7.64以降）に設定することができた。
が、iOS14対応にはこの他にATT対応を行う必要がある。
これはユーザにあった広告を表示するために必要なもので、これを導入していないとApple審査にも引っ掛かるよう。

まずはいくつかファイルを作成する。
1.ATT用Objective C++ファイル
2.ATT用 C#ファイル
3.広告表示用C#ファイル
4.pinfo.list追記用C#ファイル


1. 一つ目は[こちら](http://blog.be-style.jpn.com/article/188329627.html#03)を参考に（ほぼそのまま）作成した。
ATTの承認状態を取得している。

```obj_c++:MyObjC.mm
#import <AppTrackingTransparency/AppTrackingTransparency.h>
#import <AdSupport/AdSupport.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * ATT承認状態を取得(同期)
 **/
int Sge_Att_getTrackingAuthorizationStatus()
{
    if (@available(iOS 14, *)) {
        // enum値はそのままではC#に渡せないためにネイティブ側でintに変換
        // ATTrackingManagerAuthorizationStatusNotDetermined = 0
        // ATTrackingManagerAuthorizationStatusRestricted    = 1
        // ATTrackingManagerAuthorizationStatusDenied        = 2
        // ATTrackingManagerAuthorizationStatusAuthorized    = 3
        return (int)ATTrackingManager.trackingAuthorizationStatus;
    } else {
        return -1;
    }
}

/**
 * ATT承認を要求(非同期)
 **/
typedef void (*Callback)(int status);
void Sge_Att_requestTrackingAuthorization(Callback callback)
{
    if (@available(iOS 14, *)) {
        [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
            if (callback != nil) {
                if        (status == ATTrackingManagerAuthorizationStatusNotDetermined) {
                    NSLog(@"ATT status = NotDetermined(未設定) -> 端末設定でOK、アプリで未選択");
                } else if (status == ATTrackingManagerAuthorizationStatusRestricted) {
                    NSLog(@"ATT status = Restricted(制限あり)");
                } else if (status == ATTrackingManagerAuthorizationStatusDenied) {
                    NSLog(@"ATT status = Denied(不許可) -> 端末設定orアプリで不許可");
                } else if (status == ATTrackingManagerAuthorizationStatusAuthorized) {
                    NSLog(@"ATT status = Authorized(許可)");
                } else {
                    NSLog(@"ATT status = Other(その他)");
                }
                callback((int)status);
            }
        }];
    } else {
        NSLog(@"ATT status = iOS14 未満(非対応)");
        callback(-1);
    }
}
#ifdef __cplusplus
}
#endif
```
このファイルをPlugin>iOSに配備し、設定のiOSにチェックを入れる。
↓こんな感じ。
![スクリーンショット 2021-03-28 23.54.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/239793/09e12f87-75d0-803c-7bf5-b03915f73b4e.png)

続いて
2.Ojbective C++にアクセスするためのファイルを作成

```cs:ObjC.cs
using System;                           // for Action
using System.Runtime.InteropServices;   // for DllImport
using System.Threading;                 // for SynchronizationContext
using UnityEngine;                      // for Application

public class ObjC
{
#if UNITY_IOS
    private const string DLL_NAME = "__Internal";

    /**
     * ATT承認状態を取得(同期)
     **/
    [DllImport(DLL_NAME)]
    private static extern int Sge_Att_getTrackingAuthorizationStatus();
    public static int GetTrackingAuthorizationStatus()
    {
        if (Application.isEditor)
        {
            return -1;
        }
        return Sge_Att_getTrackingAuthorizationStatus();
    }


    /**
     * ATT承認を要求(非同期)
     **/
    [DllImport(DLL_NAME)]
    private static extern void Sge_Att_requestTrackingAuthorization(OnCompleteCallback callback);

    private delegate void OnCompleteCallback(int status);
    private static SynchronizationContext _context;
    private static Action<int> _onComplete;

    public static void RequestTrackingAuthorization(Action<int> onComplete)
    {
        if (Application.isEditor)
        {
            // 呼出元のActionの引数を0にして実行する
            onComplete?.Invoke(0);
            return;
        }
#if UNITY_IOS
        _context = SynchronizationContext.Current;
        _onComplete = onComplete;
        Sge_Att_requestTrackingAuthorization(OnRequestComplete);
#endif
    }

    [AOT.MonoPInvokeCallback(typeof(OnCompleteCallback))]
    private static void OnRequestComplete(int status)
    {
        if (_onComplete != null)
        {
            _context.Post(_ => {
                // if (_onComplete!=null) { _onComplete(status); } を省略した書き方
                _onComplete?.Invoke(status);
                _onComplete = null;
            }, null);
        }
    }
#endif
}
```

続いて
3.ATT結果を取得してATT承認要求アラートを表示＆広告の表示
バナー表示の場合、以下のようなファイルを作成

```cs:GoogleMobileAdsScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GoogleMobileAds.Api;
using GoogleMobileAds.Common;

public class GoogleMobileAdsScript : MonoBehaviour
{
    private BannerView bannerView;
    void Start()
    {
        int status = ObjC.GetTrackingAuthorizationStatus();
        // ATT状態は4択
        // ATTrackingManagerAuthorizationStatusNotDetermined = 0
        // ATTrackingManagerAuthorizationStatusRestricted    = 1
        // ATTrackingManagerAuthorizationStatusDenied        = 2
        // ATTrackingManagerAuthorizationStatusAuthorized    = 3
        if (status == 0)
        {
            // ATT設定可能 & 未承認なのでATT承認要求アラートを表示
            ObjC.RequestTrackingAuthorization(CallbackFunction);
        }
        else
        {
            if (status == 1 || status == 2)
            {
                // ATT設定不可なので、ATT承認が必要になる旨をユーザーに伝える
            }
            // Google Mobile Ads SDK を初期化
            MobileAds.Initialize(initStatus => {
                // AdMobからのコールバックはメインスレッドで呼び出される保証がないため、次のUpdate()で呼ばれるようにMobileAdsEventExecutorを使用
                MobileAdsEventExecutor.ExecuteInUpdate(() => {
                    // バナーをリクエスト
                    this.RequestBanner();
                });
            });
        }
    }

    void CallbackFunction(int status)
    {
        // ATTの状況を待ってから Google Mobile Ads SDK を初期化
        MobileAds.Initialize(initStatus => {
            // AdMobからのコールバックはメインスレッドで呼び出される保証がないため、次のUpdate()で呼ばれるようにMobileAdsEventExecutorを使用
            MobileAdsEventExecutor.ExecuteInUpdate(() => {
                // バナーをリクエスト
                this.RequestBanner();
            });
        });
    }

    private void RequestBanner()
    {
#if UNITY_ANDROID
        string adUnitId = "ca-app-pub-3940256099942544/6300978111";
#elif UNITY_IPHONE
        string adUnitId = "ca-app-pub-3940256099942544/2934735716";
#else
            string adUnitId = "unexpected_platform";
#endif
        // 画面上に320x50のバナーを用意
        this.bannerView = new BannerView(adUnitId, AdSize.Banner, AdPosition.Top);
        // 広告をリクエスト
        AdRequest request = new AdRequest.Builder().Build();
        // バナーを読み込む
        this.bannerView.LoadAd(request);
    }
}
```

4.pinfo.listにATT用の設定を追加するファイルを作成

```cs:PostBuildProcessForIosAtt.cs
#if UNITY_IOS
using System.IO;
using UnityEditor.iOS.Xcode;
using UnityEditor;
using UnityEditor.Callbacks;

namespace iOS.Editor
{
    public class PostBuildProcessForIosAtt
    {
        private const string ATT_FRAMEWORK = "AppTrackingTransparency.framework";

        [PostProcessBuild]
        public static void OnPostProcessBuild(BuildTarget buildTarget, string buildPath)
        {
            if (buildTarget != BuildTarget.iOS)
            {
                return;
            }
            // pbxに AppTrackingTransparency.framework を追加する
            var pbxPath = PBXProject.GetPBXProjectPath(buildPath);
            var pbx = new PBXProject();
            pbx.ReadFromFile(pbxPath);
            string target = GetUnityMainTargetGuidWithCompatible(pbx);
            pbx.AddFrameworkToProject(target, ATT_FRAMEWORK, true);
            pbx.WriteToFile(pbxPath);

            // Info.plist に Privacy - Tacking Usage Description(NSUserTrackingUsageDescription)を追加する
            var path = buildPath + "/Info.plist";
            var plist = new PlistDocument();
            plist.ReadFromFile(path);
            var root = plist.root;
            root.SetString("NSUserTrackingUsageDescription", "好みに合わせた広告を表示するために使用されます。");
            root.SetBoolean("GADIsAdManagerApp", true);
            plist.WriteToFile(path);
        }

        private static string GetUnityMainTargetGuidWithCompatible(PBXProject pbx)
        {
#if UNITY_2019_3_OR_NEWER
            return pbx.GetUnityFrameworkTargetGuid();
#else
            return pbx.TargetGuidByName(PBXProject.GetUnityTargetName());
#endif
        }
    }
}
#endif
```
このファイルをUnityのAsset>Editorに配備する。（Editorフォルダがなければ作成する）


この状態でiOSをビルド！！

###podfileをインストール
ビルドで生成されたフォルダをターミナルでカレントに設定し、"pod install"を実行。
Podfileを開くと書いてありますが、UnityFrameworkをターゲットにして色々インストールを行いATT導入が完了となります。

以上の手順を踏んだらxcworkspaceファイルからプロジェクトを開きビルドすることで完成します。
お試しください。