見出し画像

【iOS14対応】UnityのみでAdmobトラッキング(ATT)とローカライズに対応する


どうも、マカロンです。

今回はめちゃくちゃ久しぶりのXcodeを使わないで解決するシリーズです。

前回と前々回の記事も役に立つかもしれないので少しでも興味を持っていただけたら方はぜひのぞいてみてください!

・前回

・前々回


ということで弾3弾である今回は

iOS14以降のAdmobのトラッキング(ATT)対応とローカライズ対応を
Xcodeで設定することなく、全てUnity内で自動で行える方法
紹介していこうと思います。

それではさっそく行きましょう!




Admobトラッキング(ATT)対応について

まずはiOS14のトラッキング対応について軽く説明していこうと思います。


・これをやらないとどうなるか

まずこれを行わないとどうなるかですが、ズバリ広告がはがされます

Admob側で広告を表示に関する制限がかかったという警告文が表示され、今後の対応に合わせて制限を継続してかけるかを判断します。的なことを言ってるので要は対応しない限り広告の表示はさせないよってことですね。

なのでもしAdmobで広告を表示したい場合はさけて通れない道です。


・やらないといけない3つのこと

ひとえにAdmob対応といってもやるべきことは全部で3つあります。

1. Google Mobile Ads Unityのバージョンをv6以上にする
2.トラッキング(ATT)の表示を追加する
3.SKAdNetworkを追加する

この3つです。では一つずつ解説していきます。

まず、Google Mobile Ads Unityのバージョンについてですが
これは単純にiOS14が発表される前のバージョンはAdmob側も対応できないのでv6以上にすることでATTに対応可能になっているという話です。

二つ目はトラッキング(ATT)の表示、今回のメイン項目ですね。
これを行うことでユーザーが自分の好みに合わせて広告を表示するか、それを拒むかを選択できるようになります。これがATT対応になります。

最後にSKAdNetworkの追加です。
これはなぜやらないといけないかというと、これを追加しない場合
2番のトラッキングの追跡をユーザーが拒否した際に広告が出なくなってしまうからです。しかし、これを入れることによってユーザに拒否された場合はユーザーの好みを加味しない広告を表示することが出来るようになります。




ローカライズについて

次にローカライズについてですがこちらは何に使用するかを説明します。

まず一つ目はアプリのアイコン表示時の表記を日本語表記にしたい場合に使用します。なのでアプリのタイトルが英語の場合は不要です。後程コードを載せますので詳しい内容についてはそちらで説明させていただきます。

もう一つはトラッキングのログに表記するメッセージを設定するために使用します。これはトラッキングを許可するか選ぶユーザーに対して制作者であるこちら側から唯一メッセージを送れる部分でもあるので有効活用しましょう。




参考記事と手順

今回のこのiOS14への対処法は以下2つの記事の内容を合体させたものになりますので、ぜひ二つの記事も確認したうえで手順に進んでいただけたらと思います。


ということでまずは【Unity】AdMobをiOS14に対応させた話で紹介されているステップ1の作業を行ってください。

ステップ2、ステップ3については今回は不要です。

これを行うことでトラッキングのログ表示を任意のタイミングで行うことが出来ます。


次に【Unity】[iOS]Xcode projectの Localization 自動化で紹介されていた内容から少し改造を加えた以下のコードを追加してください。

こちらはAsset>Editorファイル内に追加してください。
Editorファイルがない場合は自分でフォルダを作成して追加しましょう!

//PostXcodeBuild.cs

using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using System.Collections;
using System.Collections.Generic;
#if UNITY_IOS
using UnityEditor.iOS.Xcode;
#endif

public class PostXcodeBuild
{
#if UNITY_IOS
   private struct InfoplistInfo
   {
       public string key;
       public string value;
       public InfoplistInfo(string str1, string str2)
       {
           key = str1;
           value = str2;
       }
   };

   private struct LocalizationInfo
   {
       public string lang;
       public bool isdefault;
       public InfoplistInfo[] infoplist;
       public LocalizationInfo(string langstr, bool flg, InfoplistInfo[] info)
       {
           lang = langstr;
           infoplist = info;
           isdefault = flg;
       }
   };
   private struct CommonInfoPlistInfo
   {
       public InfoplistInfo[] infoplist;
       public CommonInfoPlistInfo(InfoplistInfo[] info)
       {
           infoplist = info;
       }
   };

   private static LocalizationInfo[] localizationInfo = {
       new LocalizationInfo("en", false, new InfoplistInfo[]
       {new InfoplistInfo("CFBundleDisplayName",            "英語のタイトル"),
        new InfoplistInfo("NSUserTrackingUsageDescription", "Please set to Allow to avoid displaying inappropriate advertisements"),
       }),
       new LocalizationInfo("ja", true, new InfoplistInfo[]
       {new InfoplistInfo("CFBundleDisplayName",            "日本語のタイトル"),
        new InfoplistInfo("NSUserTrackingUsageDescription", "不適切な広告の表示を避けるために”トラッキングを許可”に設定してください"),
       })
   };


   private static string[] skadnetworkitems = new string[] { "cstr6suwn9.skadnetwork" };


   static void createInfoPlistString(string pjdirpath, LocalizationInfo localizationinfo)
   {
       string dirpath = Path.Combine(pjdirpath, "Unity-iPhone Tests");

       if (!Directory.Exists(Path.Combine(dirpath, string.Format("{0}.lproj", localizationinfo.lang))))
       {
           Directory.CreateDirectory(Path.Combine(dirpath, string.Format("{0}.lproj", localizationinfo.lang)));
       }
       string plistpath = Path.Combine(dirpath, string.Format("{0}.lproj/InfoPlist.strings", localizationinfo.lang));
       StreamWriter w = new StreamWriter(plistpath, false);
       foreach (InfoplistInfo info in localizationinfo.infoplist)
       {
           string convertedval = System.Text.Encoding.UTF8.GetString(
               System.Text.Encoding.Convert(
                   System.Text.Encoding.Unicode,
                   System.Text.Encoding.UTF8,
                   System.Text.Encoding.Unicode.GetBytes(info.value)
                   )
           );
           w.WriteLine(string.Format(info.key + " = \"{0}\";", convertedval));
       }
       w.Close();
   }

   static void addknownRegions(string pjdirpath, LocalizationInfo[] info)
   {
       string strtmp = "";
       string pjpath = PBXProject.GetPBXProjectPath(pjdirpath);

       foreach (LocalizationInfo infotmp in info)
       {
           strtmp += "\t\t" + infotmp.lang + ",\n";
       }
       strtmp += "\t\t);\n";

       StreamReader r = new StreamReader(pjpath);
       string prjstr = "";
       string linetmp = "";
       while (r.Peek() >= 0)
       {
           linetmp = r.ReadLine();
           if (linetmp.IndexOf("knownRegions") != -1)
           {
               prjstr += linetmp + "\n";
               prjstr += strtmp;
               while (true)
               {
                   linetmp = r.ReadLine();
                   if (linetmp.IndexOf(");") != -1)
                   {
                       break;
                   }
               }
           }
           else
           {
               prjstr += linetmp + "\n";
           }
       }
       r.Close();
       StreamWriter sw = new StreamWriter(pjpath, false);
       sw.Write(prjstr);
       sw.Close();
   }

   static void addLocalizationInfoPlist(string pjdirpath, LocalizationInfo[] info)
   {
       string plistPath = Path.Combine(pjdirpath, "Info.plist");
       PlistDocument plist = new PlistDocument();

       plist.ReadFromFile(plistPath);
       var array = plist.root.CreateArray("CFBundleLocalizations");
       foreach (LocalizationInfo infotmp in info)
       {
           array.AddString(infotmp.lang);
       }
       var rootDict = plist.root;
       foreach (LocalizationInfo infotmp in info)
       {
           if (infotmp.isdefault)
           {
               foreach (InfoplistInfo pinfo in infotmp.infoplist)
               {
                   string convertedval = System.Text.Encoding.UTF8.GetString(
                       System.Text.Encoding.Convert(
                           System.Text.Encoding.Unicode,
                           System.Text.Encoding.UTF8,
                           System.Text.Encoding.Unicode.GetBytes(pinfo.value)
                   ));
                   rootDict.SetString(pinfo.key, convertedval);
               }
           }
       }
       plist.WriteToFile(plistPath);
   }

   static void addSkAdNetworkItems(string pjdirpath, string[] skadvallist)
   {
       string plistPath = Path.Combine(pjdirpath, "Info.plist");
       PlistDocument plist = new PlistDocument();
       plist.ReadFromFile(plistPath);

       if (skadvallist != null)
       {
           var array = plist.root.CreateArray("SKAdNetworkItems");
           foreach (string value in skadvallist)
           {
               PlistElementDict dict = array.AddDict();
               dict.SetString("SKAdNetworkIdentifier", value);
           }
       }
       plist.WriteToFile(plistPath);
   }

   static void addAppTrackingTransparency(string pathToBuiltProject)
   {
       // PBXProjectクラスというのを用いてAppTrackingTransparency.frameworkを追加していきます(ステップ3)
       string pbxProjectPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
       PBXProject pbxProject = new PBXProject();
       pbxProject.ReadFromFile(pbxProjectPath);
       string targetGuid = pbxProject.GetUnityFrameworkTargetGuid();
       pbxProject.AddFrameworkToProject(targetGuid, "AppTrackingTransparency.framework", true);
       pbxProject.WriteToFile(pbxProjectPath);
   }

   [PostProcessBuild]
   public static void SetXcodePlist(BuildTarget buildTarget, string pathToBuiltProject)
   {
       if (buildTarget != BuildTarget.iOS)
       {
           return;
       }

       foreach (LocalizationInfo entry in localizationInfo)
       {
           /* add infoplist.string */
           createInfoPlistString(pathToBuiltProject, entry);
       }

       /* add knownregions to project */
       addknownRegions(pathToBuiltProject, localizationInfo);

       /* add localization to infoplist */
       addLocalizationInfoPlist(pathToBuiltProject, localizationInfo);

       /* add addSkAdNetworkItems */
       addSkAdNetworkItems(pathToBuiltProject, skadnetworkitems);

       /* add AppTrackingTransparency */
       addAppTrackingTransparency(pathToBuiltProject);
   }
#endif
}

元記事にわかりやすく解説が載っているので、今回は僕が追加した部分についてのみ補足させていただきます。

まずは

   private static LocalizationInfo[] localizationInfo = {
       new LocalizationInfo("en", false, new InfoplistInfo[]
       {new InfoplistInfo("CFBundleDisplayName",            "英語のタイトル"),
        new InfoplistInfo("NSUserTrackingUsageDescription", "Please set to Allow to avoid displaying inappropriate advertisements"),
       }),
       new LocalizationInfo("ja", true, new InfoplistInfo[]
       {new InfoplistInfo("CFBundleDisplayName",            "日本語のタイトル"),
        new InfoplistInfo("NSUserTrackingUsageDescription", "不適切な広告の表示を避けるために”トラッキングを許可”に設定してください"),
       })
   };

の部分について解説していきます。

ここで行っているのは、アプリの名前とトラッキングログに表示するメッセージの内容をそれぞれ英語、日本語で表記できるようにするための設定です。

new LocalizationInfo("en", false, new InfoplistInfo[]は英語
new LocalizationInfo("ja", true, new InfoplistInfo[]が日本語表記です。

第二引数がtrueになっている方がデフォルトの設定となるので今回は日本語の方をtrueにしています。


次に【Unity】AdMobをiOS14に対応させた話のステップ3の内容を追加している項目があります。

   static void addAppTrackingTransparency(string pathToBuiltProject)
   {
       // PBXProjectクラスというのを用いてAppTrackingTransparency.frameworkを追加していきます(ステップ3)
       string pbxProjectPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
       PBXProject pbxProject = new PBXProject();
       pbxProject.ReadFromFile(pbxProjectPath);
       string targetGuid = pbxProject.GetUnityFrameworkTargetGuid();
       pbxProject.AddFrameworkToProject(targetGuid, "AppTrackingTransparency.framework", true);
       pbxProject.WriteToFile(pbxProjectPath);
   }

こちらの記事通りにやると僕はうまくいかなかったので、上記のコードAppTrackingTransparency.frameworkの追加をすることで成功しました。




手順がややこしくなったので「やることリスト」

僕が他の記事の紹介を交えて解説したせいで手順がややこしくなってしまった気がするので改めてここに箇条書きします。

1.Google Mobile Ads Unityのバージョンをv6以上にする

2.この記事のステップ1の内容である
RequestAttDialog.mmとShowAttDialog.csの追加

3.僕が上記に載せたPostXcodeBuild.csの追加

以上です。





最後に

まとめてわかりやすくしようとしたつもりが、かえってややこしい記事になってしまっていたらすいません。

ただ僕はXcodeを使わなくても自動化することで面倒な設定とおさらばできることが一人でも多くの人に届いてくれたらうれしいなと思っています。

ではまた

ゲームを作るにはやはりお金がないとできることが限られてしまいます。なのでよろしければどうか支援してくださるとうれしいです