Files
CC-Framework.CrashReport/Assets/Editor/CrashPostProcessBuildAndroid.cs

219 lines
8.1 KiB
C#
Raw Normal View History

2024-04-03 15:13:12 +08:00
#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以上的机器
//<uses-library android:name="org.apache.http.legacy" android:required="false" />
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<XElement> 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