#if UNITY_ANDROID && UNITY_2018_2_OR_NEWER using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml.Linq; using UnityEditor; using UnityEditor.Android; namespace Editor { public class CrashPostProcessBuildAndroid : IPostGenerateGradleAndroidProject { private static readonly XNamespace AndroidNamespace = "http://schemas.android.com/apk/res/android"; private static readonly XNamespace ToolsNamespace = "http://schemas.android.com/tools"; private static readonly string networkConfigXml = "network_security_config"; public int callbackOrder { get; } public void OnPostGenerateGradleAndroidProject (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 { return; } // Get the `manifest` element. var elementManifest = manifest.Element ("manifest"); if (elementManifest == null) { return; } var elementApplication = elementManifest.Element ("application"); if (elementApplication == null) { return; } //增加必要权限 AddPermission ("android.permission.INTERNET" , elementManifest); AddPermission ("android.permission.ACCESS_NETWORK_STATE" , elementManifest); AddPermission ("android.permission.ACCESS_WIFI_STATE" , elementManifest); AddPermission ("android.permission.READ_PHONE_STATE" , elementManifest); AddPermission ("android.permission.READ_LOGS" , elementManifest); manifest.Save (manifestPath); launcherManifest.Save (launcherManifestPath); processNetworkConfigXml (path); } public static void AddPermission (string permission , XElement manifest) { var metaData = new XElement ("uses-permission"); metaData.Add (new XAttribute (AndroidNamespace + "name", permission)); //判断是否已经添加过了 var isExist = manifest.Descendants ().Any (element => element.Name.LocalName.Equals ("uses-permission") && element.Attribute (AndroidNamespace + "name")!.Value.Equals (permission)); if (!isExist) { manifest.Add (metaData); } } private static void processNetworkConfigXml (string path) { // bool isChina = true; //在application标签加上:android:networkSecurityConfig="@xml/network_security_config" var hasAdd = addNetworkSecurityConfigInApplication (path); #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 var rexXmlDir = Path.Combine (resXmlPath, $"{networkConfigXml}.xml"); if (File.Exists (rexXmlDir) || !hasAdd) { // FileUtil.DeleteFileOrDirectory (rexXmlDir); return; } if (!Directory.Exists (resXmlPath)) { Directory.CreateDirectory (resXmlPath); } // var fromScriptableObject = MonoScript.FromScriptableObject(this); var xmlPath = GetScriptsPath (nameof(CrashPostProcessBuildAndroid)); saveFile ($"{xmlPath}/{networkConfigXml}.xml", resXmlPath); } public static void saveFile (string filePathName , string toFilesPath) { FileInfo file = new FileInfo (filePathName); string newFileName = file.Name; file.CopyTo (toFilesPath + "/" + newFileName, true); } 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; } private static bool addNetworkSecurityConfigInApplication (string path) { #if UNITY_2019_3_OR_NEWER var manifestPath = Path.Combine (path, "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; try { manifest = XDocument.Load (manifestPath); } #pragma warning disable 0168 catch (IOException exception) #pragma warning restore 0168 { return false; } // Get the `manifest` element. var elementManifest = manifest.Element ("manifest"); if (elementManifest == null) { return false; } var elementApplication = elementManifest.Element ("application"); if (elementApplication == null) { return false; } //这个设置主要是为了适配9.0以上的机器 // var usesLibraryElements = elementApplication.Descendants ().Where (element => element.Name.LocalName.Equals ("uses-library")); XElement httpLegacyElement = GetElementByName (usesLibraryElements, "org.apache.http.legacy"); if (httpLegacyElement == null) { elementApplication.Add (createHttpLegacyElement ()); } manifest.Save (manifestPath); //handle anythink_network_security_config.xml XAttribute networkConfigAttribute = elementApplication.Attribute (AndroidNamespace + "networkSecurityConfig"); if (networkConfigAttribute == null) { // networkConfigAttribute.Remove (); elementApplication.Add (new XAttribute (AndroidNamespace + "networkSecurityConfig", $"@xml/{networkConfigXml}")); manifest.Save (manifestPath); return true; } return false; } public static XElement createHttpLegacyElement () { var httpFeautre = new XElement ("uses-library"); httpFeautre.Add (new XAttribute (AndroidNamespace + "name", "org.apache.http.legacy")); httpFeautre.Add (new XAttribute (AndroidNamespace + "required", "false")); return httpFeautre; } 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; } } } #endif