#if UNITY_ANDROID using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml.Linq; using UnityEngine; using UnityEditor; using UnityEditor.Android; namespace Topon_Adapter.Editor { public class AD_BuildAndroidProcess : IPostGenerateGradleAndroidProject { private static readonly XNamespace AndroidNamespace = "http://schemas.android.com/apk/res/android"; private static readonly XNamespace ToolsNamespace = "http://schemas.android.com/tools"; public void OnPostGenerateGradleAndroidProject (string path) { ProcessAndroidManifest (path); } public static void ProcessAndroidManifest (string path) { #if UNITY_2019_3_OR_NEWER var manifestPath = Path.Combine (path, "src/main/AndroidManifest.xml"); var launcherManifestPath = Path.Combine (path, "../launcher/src/main/AndroidManifest.xml"); #else var manifestPath = Path.Combine(path, "unityLibrary/src/main/AndroidManifest.xml"); #endif // var manifestPath = Path.Combine(path, "src/main/AndroidManifest.xml"); XDocument manifest; XDocument launcherManifest; try { manifest = XDocument.Load (manifestPath); launcherManifest = XDocument.Load (launcherManifestPath); } #pragma warning disable 0168 catch (IOException exception) #pragma warning restore 0168 { ATLog.log ("[BuildAndroidProcess] AndroidManifest.xml is missing."); return; } #if UNITY_2019_3_OR_NEWER var resXmlPath = Path.Combine(path, "src/main/res/xml"); #else var resXmlPath = Path.Combine(path, "unityLibrary/src/main/res/xml"); #endif if (!Directory.Exists(resXmlPath)) { Directory.CreateDirectory(resXmlPath); } var xmlPath = GetScriptsPath("AD_BuildAndroidProcess"); saveFile($"{xmlPath}/alex_tt_file_path.xml", resXmlPath); saveFile($"{xmlPath}/anythink_bk_tt_file_path.xml", resXmlPath); // Get the `manifest` element. var elementManifest = manifest.Element ("manifest"); if (elementManifest == null) { ATLog.log ("[BuildAndroidProcess] AndroidManifest.xml is invalid."); return; } var elementApplication = elementManifest.Element ("application"); if (elementApplication == null) { ATLog.log ("[BuildAndroidProcess] AndroidManifest.xml is invalid."); return; } ToSingleTop (elementManifest); var xManifestElements = elementManifest.Descendants (); var xApplicationElements = elementApplication.Descendants (); var useQueries = xManifestElements.Where (element => element.Name.LocalName.Equals ("package")); XElement tencentElement = GetElementByName (useQueries, "com.tencent.mm"); if (tencentElement == null) { elementManifest.Add (CreateQueries ()); } var wxElements = xApplicationElements .Where (element => element.Name.LocalName.Equals ("activity")) .Where (element => element.Attribute (AndroidNamespace + "name")?.Value == ".wxapi.WXEntryActivity") .ToList (); foreach (var wxElement in wxElements) { wxElement.Remove (); } elementApplication.Add (CreateActivityXML ()); var elementlauncherManifest = launcherManifest.Element ("manifest"); if (elementlauncherManifest == null) { ATLog.log ("[BuildAndroidProcess] Launcher AndroidManifest.xml is invalid."); return; } var elementlauncherApplication = elementlauncherManifest.Element ("application"); if (elementlauncherApplication == null) { ATLog.log ("[BuildAndroidProcess] Launcher AndroidManifest.xml is invalid."); return; } var launcherProviders = elementlauncherApplication.Descendants () .Where (element => element.Name.LocalName.Equals ("provider")) .Where (element => element.Attribute (AndroidNamespace + "name")?.Value == "com.bytedance.sdk.openadsdk.TTFileProvider") .ToList (); foreach (var launcherProvider in launcherProviders) { launcherProvider.Remove (); } elementlauncherApplication.Add (CreateCSJGromore ()); SetOrAddAttribute (elementlauncherApplication, AndroidNamespace + "allowBackup", "false"); SetOrAddAttribute (elementlauncherApplication, ToolsNamespace + "replace", "android:allowBackup"); var elementMainManifest = manifest.Element ("manifest"); var elementMainApplication = elementMainManifest.Element ("application"); var mainElements = elementMainApplication.Descendants ().Where (element => element.Name.LocalName.Equals ("provider")); XElement mainElement = GetElementByName (mainElements, "com.bytedance.sdk.openadsdk.TTFileProvider"); if (mainElement == null) { //增加穿山甲配置 // elementMainApplication.Add (CreateCSJGromore ()); } // Save the updated manifest file. manifest.Save (manifestPath); launcherManifest.Save (launcherManifestPath); } public static void saveFile(string filePathName , string toFilesPath) { if (string.IsNullOrWhiteSpace(filePathName) || !File.Exists(filePathName)) { ATLog.log ($"[BuildAndroidProcess] Skip missing file copy: {filePathName}"); return; } FileInfo file = new FileInfo(filePathName); string newFileName = file.Name; file.CopyTo(toFilesPath + "/" + newFileName, true); } /// /// 增加微信开放平台的适配 /// public static XElement CreateActivityXML () { var metaData = new XElement ("activity"); metaData.Add (new XAttribute (AndroidNamespace + "name", ".wxapi.WXEntryActivity")); metaData.Add (new XAttribute (AndroidNamespace + "label", "@string/app_name")); metaData.Add (new XAttribute (AndroidNamespace + "theme", "@android:style/Theme.Translucent.NoTitleBar")); metaData.Add (new XAttribute (AndroidNamespace + "exported", "true")); metaData.Add (new XAttribute (AndroidNamespace + "taskAffinity", Application.identifier)); metaData.Add (new XAttribute (AndroidNamespace + "launchMode", "singleTop")); return metaData; } public static XElement CreateQueries () { var metaData = new XElement ("queries"); var packageData = new XElement ("package"); packageData.Add (new XAttribute (AndroidNamespace + "name", "com.tencent.mm")); metaData.Add (packageData); return metaData; } private static XElement GetElementByName (IEnumerable elements, string name) { foreach (var element in elements) { var attributes = element.Attributes (); if (attributes.Any (attribute => attribute.Name.Namespace.Equals (AndroidNamespace) && attribute.Name.LocalName.Equals ("name") && attribute.Value.Equals (name))) { return element; } } return null; } public static string GetScriptsPath (string scriptName) { string[] path = UnityEditor.AssetDatabase.FindAssets(scriptName); if(path.Length >1) { // Debug.LogError("有同名文件"+_scriptName+"获取路径失败"); return null; } //将字符串中得脚本名字和后缀统统去除掉 string _path = AssetDatabase.GUIDToAssetPath(path[0]).Replace((@"/" +scriptName +".cs"),""); return _path; } public static XElement CreateCSJGromore () { // ReSharper disable once InvalidXmlDocComment /** * */ var providerData = new XElement ("provider"); providerData.Add (new XAttribute (AndroidNamespace + "name" , "com.bytedance.sdk.openadsdk.TTFileProvider")); providerData.Add (new XAttribute (AndroidNamespace + "authorities" , "${applicationId}.TTFileProvider")); providerData.Add (new XAttribute (AndroidNamespace + "exported" , "false")); providerData.Add (new XAttribute (AndroidNamespace + "grantUriPermissions" , "true")); providerData.Add (new XAttribute (ToolsNamespace + "replace" , "android:authorities")); var metaData = new XElement ("meta-data"); metaData.Add (new XAttribute (AndroidNamespace + "name" , "android.support.FILE_PROVIDER_PATHS")); metaData.Add (new XAttribute (AndroidNamespace + "resource" , "@xml/anythink_bk_tt_file_path")); providerData.Add (metaData); return providerData; } public static void ToSingleTop (XElement manifest) { var elements = manifest.Descendants ().Where (element => element.Name.LocalName.Equals ("activity")); // 如果这个activity已经有了 android:launchMode="singleTask",则不再添加 XElement elementByName = GetElementByName (elements , "com.unity3d.player.UnityPlayerActivity"); if (elementByName == null) { ATLog.log ("[BuildAndroidProcess] UnityPlayerActivity not found, skip launchMode patch."); return; } //此处将 android:launchMode="singleTask" 改为 android:launchMode="singleTop" SetOrAddAttribute (elementByName, AndroidNamespace + "launchMode", "singleTop"); } private static void SetOrAddAttribute (XElement element, XName attributeName, string value) { var attribute = element.Attribute (attributeName); if (attribute == null) { element.Add (new XAttribute (attributeName, value)); return; } attribute.SetValue (value); } public int callbackOrder { get; } } } #endif