しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Unity で iOS 14 の ATT 対応の Xcode 設定の多言語化を自動化する

※ これは 2021/04/09 時点の Unity 2020.3.3f1, Xcode 12.4 の情報です

最新版では動作が異なる可能性がありますのでご注意ください

Xcode の設定を自動化したものの、これでもまだ問題があって、下記のままだと多言語対応ができていない

というわけで今回は ATT の許可ダイアログで表示される文言を日本語と英語両方に対応した上で Xcode の手順を自動化してみたい

この場合、Unity の公式 API だけでは自動化できないため、下記の GitHub のコードをお借りする

ライセンス表記がないため改変や二次配布などはできないがそのまま使用するだけなら問題なさそう

ダウンロードしたソース内の Assets/Editor/Xcodeディレクトリだけをコピーして Unity プロジェクトの Assets/Editor 配下にペーストする

Xcode ディレクト

次に Assets/Editor/iOS/Localization/en.lprojディレクトリを作り、配下に InfoPlist.strings というファイルを作成する

InfoPlist.strings

InfoPlist.strings の中身はこんな感じ

"NSUserTrackingUsageDescription" = "It'll be used to display advertisements and analyze usage.";

同じように Assets/Editor/iOS/Localization/ja.lprojディレクトリを作り、配下に下記のような InfoPlist.strings というファイルを作成する

"NSUserTrackingUsageDescription" = "上記は広告の表示や利用状況の分析に利用されます";

あとは PostprocessBuild.cs を下記のように変更

using System.IO;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;

/// <summary>
/// ビルド後処理。
/// </summary>
public class PostprocessBuild : MonoBehaviour
{
    /// <summary>
    /// ビルド後処理
    /// </summary>
    /// <param name="buildTarget">ビルドターゲット情報</param>
    /// <param name="path">出力先パス</param>
    [PostProcessBuild(1)]
    public static void OnPostprocessBuild(BuildTarget buildTarget, string path)
    {
        if (buildTarget == BuildTarget.iOS)
        {
            BuildIOS(buildTarget, path);
        }
    }

    /// <summary>
    /// iOS 用ビルド後処理
    /// </summary>
    /// <param name="buildTarget">ビルドターゲット情報</param>
    /// <param name="path">出力先パス</param>
    public static void BuildIOS(BuildTarget buildTarget, string path)
    {
        var exportPath = new DirectoryInfo(path).FullName;
        var projectPath = new DirectoryInfo(
            Path.Combine(Path.Combine(exportPath, "Unity-iPhone.xcodeproj"), "project.pbxproj")).FullName;

        // Xcode プロジェクトファイルを読み込む
        var project = new Strings.iOS.Xcode.PBXProject();
        project.ReadFromFile(projectPath);

        // Xcode プロジェクト内のターゲット参照
        var target = project.TargetGuidByName("Unity-iPhone");
        var frameworks = project.TargetGuidByName("UnityFramework");

        // ATT 用フレームワーク参照追加
        project.AddFrameworkToProject(frameworks, "AppTrackingTransparency.framework", false);
        
        var plist = new Strings.iOS.Xcode.PlistDocument();
        var plistPath = Path.Combine(path, "Info.plist");
        plist.ReadFromFile(plistPath);

        // 言語設定
        var locales = new string[] { "en", "ja" };
        plist.root.SetString("CFBundleDevelopmentRegion", locales[0]);
        plist.WriteToFile(plistPath);

        // 言語リソース追加
        project.ClearVariantGroupEntries("InfoPlist.strings");
        foreach (var locale in locales)
        {
            var srcDir = Path.Combine(Path.Combine(Application.dataPath, "Editor/iOS/Localization"), $"{locale}.lproj");
            var destDir = new DirectoryInfo(Path.Combine(exportPath, $"{locale}.lproj")).FullName;
            CopyAndReplaceDirectory(srcDir, destDir, true);

            project.AddLocalization("InfoPlist.strings", locale, $"{locale}.lproj/InfoPlist.strings");
        }

        // Xcode のプロジェクトファイルに書き戻し
        project.WriteToFile(projectPath);
    }

    /// <summary>
    /// サブディレクトリも含めてコピー
    /// </summary>
    /// <param name="srcPath">コピー元</param>
    /// <param name="dstPath">コピー先</param>
    /// <param name="isOverWrite">上書きフラグ</param>
    public static void CopyAndReplaceDirectory(string srcPath, string dstPath, bool isOverWrite = true)
    {
        if (isOverWrite)
        {
            if (Directory.Exists(dstPath))
                Directory.Delete(dstPath, true);
            if (File.Exists(dstPath))
                File.Delete(dstPath);
        }

        if (!Directory.Exists(dstPath))
            Directory.CreateDirectory(dstPath);

        foreach (var file in Directory.GetFiles(srcPath))
        {
            if (file.EndsWith(".meta"))
            {
                continue;
            }
            File.Copy(file, Path.Combine(dstPath, Path.GetFileName(file)), isOverWrite);
        }

        foreach (var dir in Directory.GetDirectories(srcPath))
            CopyAndReplaceDirectory(dir, Path.Combine(dstPath, Path.GetFileName(dir)));
    }
}

Unity 公式の PBXProjectPlistDocument の代わりに今回お借りした Strings.iOS.Xcode.PBXProjectStrings.iOS.Xcode.PlistDocument を利用して、InfoPlist.strings を多言語対応させている

これでビルドしてみると・・・

InfoPlist.strings の多言語化

Unity-iPhone Tests/Supporting Files/InfoPlist.stringsUnity-iPhone のターゲット向けにも英語と日本語で多言語化されていた!