Unity - 記錄打包成android脖捻,處理應(yīng)用名多語言

Unity版本:2019.4.5f1兆衅,本文實現(xiàn)的多語言為簡體中文羡亩,繁體中文

前言:

如下圖所示,在PlayerSettings里面只能設(shè)置基礎(chǔ)的應(yīng)用名;


下面記錄我在Unity打包成android時雷袋,實現(xiàn)應(yīng)用名的本地化的過程:

方式一(未成功):在Assets/Plugins/Android/目錄下添加res

首先要了解片排,我們配置的默認(rèn)應(yīng)用名在導(dǎo)成android時會在src→main→res→values目錄下生成strings.xml文件



strings.xml文件內(nèi)容如下:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">My Game</string>
</resources>

因此率寡,我們只需要依照android多語言的方式倚搬,在src→main→res目錄下添加:values-zh-rCN,values-zh-rTW(我這里只添加繁體和簡體中文捅僵,更多語言請自行查找android的對應(yīng)語言代碼),并分別創(chuàng)建strings.xml文件上荡,內(nèi)容如下:

  • values-zh-rCN
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">我的游戲</string>
</resources>
  • values-zh-rTW
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">我的遊戲</string>
</resources>

在unity工程中馒闷,我們只需要Plugins→Android目錄下創(chuàng)建res目錄纳账,其里面內(nèi)容如下:



如此之后打包確并沒有成功疏虫,并有如下警告信息:

OBSOLETE - Providing Android resources in Assets/Plugins/Android/res is deprecated, please move your resources to an AAR or an Android Library. 
See "AAR plug-ins and Android Libraries" section of the Manual for more details.
UnityEditor.BuildPlayerWindow:BuildPlayerAndRun() (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPlayerWindow.cs:136)

由該警告可知,直接添加 Assets/Plugins/Android/res的方式已經(jīng)被放棄了呢袱,需要打包成aar翅敌,由此引出方式二哼御。
參考鏈接:Unity Android應(yīng)用名稱的國際化

方式二:打包res到aar

這一步需要了解較多android知識,這里簡要描述下:
1.創(chuàng)建android工程看靠,添加module
2.在module的創(chuàng)建values-zh-rCN液肌,values-zh-rTW目錄和語言文件
3.將module打包成aar
4.將aar拷貝到Assets/Plugins/Android/目錄下

我在項目中使用了I2 Localization實現(xiàn)多語言嗦哆,當(dāng)時沒有了解I2 Localization機(jī)制,和其產(chǎn)生了沖突粥喜,導(dǎo)致部分語言未生效

方式三:在Assets/Plugins/Android/目錄下添加res橘券,同時在 build.gradle使用task

1.添加res目錄(過程同方法一)
2.在Bulid Settings → Player Settings → Android → Publishing Settings 中勾選Custom Launcher Gradle Templ:


image.png

3.在生成的launcherTemplate.gradle文件末尾添加如下代碼(使用task在編譯時將前面添加的res目錄復(fù)制到正確的地址):

task localizeAppName(type: Copy) {
    from("${project.rootDir}/unityLibrary/unity-android-resources/res/") {
        include "**"
    }
    into "${project.projectDir}/src/main/res/"
}

preBuild.dependsOn(localizeAppName)

同樣由于使用了I2 Localization锋华,導(dǎo)致部分語言未生效,這里可以通過類似如下的代碼刪除I2 Localization生成的strings.xml文件:
注意: 1.我這里只針對自己項目移除了簡體中文和繁體中文
?????????2.如果strings.xml未能成功移除衍腥,在需要將工程導(dǎo)出成Android項目纳猫,找到正確的文件路徑進(jìn)行移除

/* 刪除自動生成的多余values-zh-rCN */
task appNameDeleteCN(type: Delete) {
    delete "${project.projectDir}/src/main/res/values-zh-rCN/strings.xml"
    delete "${project.projectDir}/src/main/res/values-zh-rTW/strings.xml"
}

preBuild.dependsOn(appNameDeleteCN)

參考鏈接:Unity2018 設(shè)置 Android 程序名稱的多語言

方式四:參考I2 Localization续担,在unity中動態(tài)生成strings.xml

這里不多贅述了活孩,直接貼出其PostProcessBuild_Android類

#if UNITY_ANDROID
using UnityEditor.Callbacks;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;

namespace I2.Loc
{
   public class PostProcessBuild_Android
   {
        // Post Process Scene is a hack, because using PostProcessBuild will be called after the APK is generated, and so, I didn't find a way to copy the new files
        [PostProcessScene]
        public static void OnPostProcessScene()
        {
            #if UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
                bool isFirstScene = (EditorBuildSettings.scenes.Length>0 && EditorBuildSettings.scenes[0].path == EditorApplication.currentScene);
            #else
                bool isFirstScene = UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex <= 0;
            #endif

            if (!EditorApplication.isPlayingOrWillChangePlaymode &&
                (EditorUserBuildSettings.activeBuildTarget == BuildTarget.Android) &&
                isFirstScene)
            {
                string projPath = System.IO.Path.GetFullPath(Application.streamingAssetsPath + "/../../Temp/StagingArea");
                //string projPath = System.IO.Path.GetFullPath(Application.dataPath+ "/Plugins/Android");
                PostProcessAndroid(BuildTarget.Android, projPath);
            }
        }

        //[PostProcessBuild(10000)]
        public static void PostProcessAndroid(BuildTarget buildTarget, string pathToBuiltProject)
      {
         if (buildTarget!=BuildTarget.Android)
            return;

            if (LocalizationManager.Sources.Count <= 0)
            LocalizationManager.UpdateSources();

            // Get language with variants, but also add it without the variant to allow fallbacks (e.g. en-CA also adds en)
         var langCodes = LocalizationManager.GetAllLanguagesCode(false).Concat( LocalizationManager.GetAllLanguagesCode(true) ).Distinct().ToList();

         if (langCodes.Count <= 0)
            return;
         string stringXML =  "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"+
                        "<resources>\n"+
                        "    <string name=\"app_name\">{0}</string>\n"+
                        "</resources>";

            SetStringsFile( pathToBuiltProject+"/res/values", "strings.xml", stringXML, LocalizationManager.GetAppName(langCodes[0]) );


         var list = new List<string>();
         list.Add( pathToBuiltProject + "/res/values" );
         foreach (var code in langCodes)
         {
                // Android doesn't use zh-CN or zh-TW, instead it uses: zh-rCN, zh-rTW, zh
                string fixedCode = code;
                if (fixedCode.StartsWith("zh", System.StringComparison.OrdinalIgnoreCase))
                {
                    string googleCode = GoogleLanguages.GetGoogleLanguageCode(fixedCode);
                    if (googleCode==null) googleCode = fixedCode;
                    fixedCode = (googleCode == "zh-CN") ? "zh-CN" : googleCode;
                }
            fixedCode = fixedCode.Replace("-", "-r");

                string dir = pathToBuiltProject + "/res/values-" + fixedCode;

                SetStringsFile( dir, "strings.xml", stringXML, LocalizationManager.GetAppName(code) );
         }
      }

      static void CreateFileIfNeeded ( string folder, string fileName, string text )
      {
         try
         {
            if (!System.IO.Directory.Exists( folder ))
               System.IO.Directory.CreateDirectory( folder );

            if (!System.IO.File.Exists( folder + "/"+fileName ))
               System.IO.File.WriteAllText( folder + "/"+fileName, text );
         }
         catch (System.Exception e)
         {
            Debug.Log( e );
         }
      }

        static void SetStringsFile(string folder, string fileName, string stringXML, string appName)
        {
            try
            {
                appName = appName.Replace("&", "&amp;").Replace("<", "&lt;").Replace(">", "&gt;").Replace("\"", "\\\"").Replace("'", "\\'");
                appName = appName.Replace("\r\n", string.Empty).Replace("\n", string.Empty).Replace("\r", string.Empty);

                if (!System.IO.Directory.Exists(folder))
                    System.IO.Directory.CreateDirectory(folder);

                if (!System.IO.File.Exists(folder + "/" + fileName))
                {
                    // create the string file if it doesn't exist
                    stringXML = string.Format(stringXML, appName);
                }
                else
                {
                    stringXML = System.IO.File.ReadAllText(folder + "/" + fileName);
                    // find app_name
                    var pattern = "\"app_name\">(.*)<\\/string>";
                    var regexPattern = new System.Text.RegularExpressions.Regex(pattern);
                    if (regexPattern.IsMatch(stringXML))
                    {
                        // Override the AppName if it was found
                        stringXML = regexPattern.Replace(stringXML, string.Format("\"app_name\">{0}</string>", appName));
                    }
                    else
                    {
                        // insert the appName if it wasn't there
                        int idx = stringXML.IndexOf("<resources>");
                        if (idx > 0)
                            stringXML = stringXML.Insert(idx + "</resources>".Length, string.Format("\n    <string name=\"app_name\">{0}</string>\n", appName));
                    }
                }
                System.IO.File.WriteAllText(folder + "/" + fileName, stringXML);
            }
            catch (System.Exception e)
            {
                Debug.Log(e);
            }
        }
    }
}
#endif
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市训裆,隨后出現(xiàn)的幾起案子边琉,更是在濱河造成了極大的恐慌,老刑警劉巖族扰,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件定欧,死亡現(xiàn)場離奇詭異砍鸠,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)类茂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來厚骗,“玉大人兢哭,你說我怎么就攤上這事迟螺。” “怎么了锉桑?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵窍株,是天一觀的道長球订。 經(jīng)常有香客問我,道長微驶,這世上最難降的妖魔是什么开睡? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任篇恒,我火速辦了婚禮,結(jié)果婚禮上蘸秘,老公的妹妹穿的比我還像新娘蝗茁。我一直安慰自己,他們只是感情好颈嚼,可當(dāng)我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布阻课。 她就那樣靜靜地躺著,像睡著了一般抹恳。 火紅的嫁衣襯著肌膚如雪署驻。 梳的紋絲不亂的頭發(fā)上旺上,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天,我揣著相機(jī)與錄音窃这,去河邊找鬼征候。 笑死倍奢,一個胖子當(dāng)著我的面吹牛垒棋,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播畔裕,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼扮饶,長吁一口氣:“原來是場噩夢啊……” “哼乍构!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起岂丘,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤奥帘,失蹤者是張志新(化名)和其女友劉穎仪召,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體已旧,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡运褪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年吐句,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片攀芯。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡文虏,死狀恐怖氧秘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情搔确,我是刑警寧澤灭忠,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布弛作,位于F島的核電站,受9級特大地震影響机隙,放射性物質(zhì)發(fā)生泄漏萨西。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一印颤、第九天 我趴在偏房一處隱蔽的房頂上張望穿肄。 院中可真熱鬧年局,春花似錦际看、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至僵朗,卻和暖如春赖欣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背验庙。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工顶吮, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人粪薛。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像违寿,于是被迫代替她去往敵國和親湃交。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 應(yīng)用程序根據(jù)系統(tǒng)設(shè)置語言實現(xiàn)多語言適配 應(yīng)用程序默認(rèn)只要配置不同語言的文件藤巢,在啟動應(yīng)用時都會根據(jù)系統(tǒng)語言而加載對應(yīng)...
    dingyx閱讀 25,570評論 5 26
  • 1搞莺、字符串本地化如何工作 默認(rèn)情況下,Android將英語作為主要語言并加載string資源從res?values...
    Kotyo閱讀 2,064評論 3 8
  • 添加多語言資源文件 第一步: 第二步: 第三步: 第四步: 第五步: 以上步驟僅僅是添加values-zh-rCN...
    CQ_TYL閱讀 3,533評論 0 6
  • 夜鶯2517閱讀 127,717評論 1 9
  • 版本:ios 1.2.1 亮點: 1.app角標(biāo)可以實時更新天氣溫度或選擇空氣質(zhì)量掂咒,建議處女座就不要選了才沧,不然老想...
    我就是沉沉閱讀 6,883評論 1 6