using System.Collections.Generic; using System.IO; using UnityEditor; using UnityEditor.Callbacks; using UnityEngine; using UnityEngine.Rendering; using Wheels.Unity; [InitializeOnLoad] public partial class IssueFix : EditorWindow { static ARSDKConfig sdkConfig; static Texture2D logo; static bool allFixed = true; /// /// 目标系统平台,必须是Android /// static bool targetPlatform; /// /// SDK是否为C/S架构,如果是的话需要向ScriptingDefineSymbols添加CS符号,否则移除 /// static bool clientServerMode; /// /// GraphicsAPI必须是OpenGLES3或OpenGLES2,否则为false /// static bool graphicsAPIOK; /// /// Android最小支持sdk版本,大于等于27为true /// static bool minimum_API_Level; /// /// 编译此项目用到的sdk版本 /// static bool target_API_Level; /// /// 是Mono还是IL2CPP,IL2CPP为true /// static bool scripting_Backend; /// /// 目标平台为ARM64为true /// static bool target_Architectures; /// /// 允许unsafe为true /// static bool allow_Unsafe_Code; /// /// 禁用MultiThreadedRendering为true /// static bool disableMultiThreadedRendering; static IssueFix() { AssetDatabase.importPackageCompleted -= AssetDatabase_importPackageCompleted; AssetDatabase.importPackageCompleted += AssetDatabase_importPackageCompleted; } private void OnEnable() { Init(); FixTags(); } private static void AssetDatabase_importPackageCompleted(string packageName) { if (packageName.Contains("EZXR_ARGlass_SDK")) { string filePath = "EZXR_CICD.cfg"; if (File.Exists(filePath)) { FixAllIssues(); File.WriteAllText(filePath, "AllFixed"); } else { ShowWindow(); } } } [MenuItem("ARSDK/Project Settings", false, 50)] public static void ShowWindow() { EditorWindow window = EditorWindow.GetWindow(typeof(IssueFix), false, "Project Settings"); window.minSize = new Vector2(300, 300); } [DidReloadScripts] /// /// 进行所有代码之前必须先执行的初始化操作,取到ARSDK的配置文件 /// static void Init() { string filePath = "Assets/EZXRGlassSDK/Editor/ARSDKConfig.asset"; if ((AssetDatabase.LoadAssetAtPath(filePath, typeof(ARSDKConfig)) as ARSDKConfig) == null) { filePath = AssetDatabase.GUIDToAssetPath("2c84fdf00cdace44ba329395d9e29d08"); } sdkConfig = AssetDatabase.LoadAssetAtPath(filePath, typeof(ARSDKConfig)) as ARSDKConfig; if (sdkConfig != null) { SetAbilitiesSymbols(); CheckAllIssues(); if (!allFixed) { ShowWindow(); } } } partial void OnGUI_X1(); static bool foldout_IssueFix = true; GUIStyle label_Red; //static bool foldout_Settings = true; void OnGUI() { if (logo == null) { logo = Resources.Load("ezxr_logo"); } GUILayout.Button(logo, GUILayout.Height(200)); EditorGUILayout.Separator(); CheckAllIssues(); UnityEditorGUI.DrawLine(); foldout_IssueFix = EditorGUILayout.Foldout(foldout_IssueFix, "Project IssueFix"); if (foldout_IssueFix) { label_Red = new GUIStyle(EditorStyles.label); label_Red.normal.textColor = Color.red; if (allFixed) { EditorGUILayout.HelpBox("Everything is OK!", MessageType.Info); } else { EditorGUILayout.HelpBox("For AR Glass Project, all issues below must be fixed, or your project cannot run on AR Glass devices!", MessageType.Warning); } EditorGUILayout.Separator(); #region 通用修复项 if (!targetPlatform) { GUILayout.BeginHorizontal(); GUILayout.Label("Platform:"); GUILayout.FlexibleSpace(); GUILayout.Label("Should be 'Android'", label_Red); if (GUILayout.Button("Fix")) { FixTargetPlatform(); } GUILayout.EndHorizontal(); EditorGUILayout.Separator(); } if (!clientServerMode) { GUILayout.BeginHorizontal(); GUILayout.Label("C/S:"); GUILayout.FlexibleSpace(); GUILayout.Label("Should be Fixed", label_Red); if (GUILayout.Button("Fix")) { FixClientServerMode(); } GUILayout.EndHorizontal(); EditorGUILayout.Separator(); } if (!graphicsAPIOK) { GUILayout.BeginHorizontal(); GUILayout.Label("GraphicsAPI Status:"); GUILayout.FlexibleSpace(); GUILayout.Label("Should be 'OpenGLES3 or OpenGLES2'", label_Red); if (GUILayout.Button("Fix")) { FixGraphicsAPI(); } GUILayout.EndHorizontal(); EditorGUILayout.Separator(); } if (!minimum_API_Level) { GUILayout.BeginHorizontal(); GUILayout.Label("Minimum API Level:"); GUILayout.FlexibleSpace(); GUILayout.Label("Recommend be '" + (AndroidSdkVersions)sdkConfig.recommendedAPILevel + "'", label_Red); if (GUILayout.Button("Fix")) { FixMinimumAPILevel(); } GUILayout.EndHorizontal(); EditorGUILayout.Separator(); } if (!target_API_Level) { GUILayout.BeginHorizontal(); GUILayout.Label("Target API Level: "); GUILayout.FlexibleSpace(); GUILayout.Label("Recommend be '" + sdkConfig.recommendedAPILevel + "'", label_Red); if (GUILayout.Button("Fix")) { FixTargetAPILevel(); } GUILayout.EndHorizontal(); EditorGUILayout.Separator(); } if (!scripting_Backend) { GUILayout.BeginHorizontal(); GUILayout.Label("Scripting Backend: "); GUILayout.FlexibleSpace(); GUILayout.Label("Should be 'IL2CPP'", label_Red); if (GUILayout.Button("Fix")) { FixScriptingBackend(); } GUILayout.EndHorizontal(); EditorGUILayout.Separator(); } if (!target_Architectures) { GUILayout.BeginHorizontal(); GUILayout.Label("Target Architectures: "); GUILayout.FlexibleSpace(); GUILayout.Label("Should be 'ARM64'", label_Red); if (GUILayout.Button("Fix")) { FixTargetArchitectures(); } GUILayout.EndHorizontal(); EditorGUILayout.Separator(); } if (!allow_Unsafe_Code) { GUILayout.BeginHorizontal(); GUILayout.Label("Allow Unsafe Code: "); GUILayout.FlexibleSpace(); GUILayout.Label("Should be 'Checked'", label_Red); if (GUILayout.Button("Fix")) { FixAllowUnsafeCode(); } GUILayout.EndHorizontal(); EditorGUILayout.Separator(); } if (!disableMultiThreadedRendering) { GUILayout.BeginHorizontal(); GUILayout.Label("MultiThreadedRendering: "); GUILayout.FlexibleSpace(); GUILayout.Label("MultiThreadedRendering must be 'Disabled'", label_Red); if (GUILayout.Button("Fix")) { FixMultiThreadedRendering(); } GUILayout.EndHorizontal(); } #endregion OnGUI_X1(); } UnityEditorGUI.DrawLine(); //foldout_Settings = EditorGUILayout.Foldout(foldout_Settings, "Project XR Abilities"); //if (foldout_Settings) //{ // EditorGUILayout.BeginVertical(EditorStyles.helpBox); // EditorGUILayout.BeginHorizontal(); // projectConfig.spatialTracking = EditorGUILayout.ToggleLeft("spatialTracking", projectConfig.spatialTracking, GUILayout.Width(150)); // projectConfig.planeDetection = EditorGUILayout.ToggleLeft("planeDetection", projectConfig.planeDetection, GUILayout.Width(150)); // projectConfig.imageDetection = EditorGUILayout.ToggleLeft("imageDetection", projectConfig.imageDetection, GUILayout.Width(150)); // EditorGUILayout.EndHorizontal(); // EditorGUILayout.BeginHorizontal(); // projectConfig.spatialMesh = EditorGUILayout.ToggleLeft("spatialMesh", projectConfig.spatialMesh, GUILayout.Width(150)); // projectConfig.handTracking = EditorGUILayout.ToggleLeft("handTracking", projectConfig.handTracking, GUILayout.Width(150)); // projectConfig.spatialPositioning = EditorGUILayout.ToggleLeft("spatialPositioning", projectConfig.spatialPositioning, GUILayout.Width(150)); // EditorGUILayout.EndHorizontal(); // projectConfig.miraCast = EditorGUILayout.ToggleLeft("MiraCast", projectConfig.miraCast, GUILayout.Width(150)); // EditorGUILayout.BeginHorizontal(); // EditorGUILayout.EndHorizontal(); // EditorGUILayout.EndVertical(); //} } static partial void CheckAllIssues_X1(); static void CheckAllIssues() { #region 通用修复项 //目标系统平台必须是Android BuildTarget buildTarget = EditorUserBuildSettings.activeBuildTarget; if (buildTarget == BuildTarget.Android) { targetPlatform = true; allFixed &= targetPlatform; } else { targetPlatform = false; allFixed &= targetPlatform; } string symbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android); if (sdkConfig.clientServerMode) { if (string.IsNullOrEmpty(symbols)) { clientServerMode = false; } else if (symbols.Contains("EZXRCS")) { clientServerMode = true; } else { clientServerMode = false; } } else { if (string.IsNullOrEmpty(symbols)) { clientServerMode = true; } else if (symbols.Contains("EZXRCS")) { clientServerMode = false; } else { clientServerMode = true; } } //GraphicsAPI必须是OpenGLES3或OpenGLES2,否则为false GraphicsDeviceType[] graphicsAPIs = PlayerSettings.GetGraphicsAPIs(BuildTarget.Android); foreach (GraphicsDeviceType item in graphicsAPIs) { if (item != GraphicsDeviceType.OpenGLES3 && item != GraphicsDeviceType.OpenGLES2) { graphicsAPIOK = false; allFixed &= graphicsAPIOK; break; } else { graphicsAPIOK = true; allFixed &= graphicsAPIOK; } } //Android最小支持sdk版本 AndroidSdkVersions androidSdkVersions = PlayerSettings.Android.minSdkVersion; if ((int)androidSdkVersions >= sdkConfig.recommendedAPILevel) { minimum_API_Level = true; allFixed &= minimum_API_Level; } else { minimum_API_Level = false; allFixed &= minimum_API_Level; } //用于编译项目的sdk版本 AndroidSdkVersions targetAndroidSdkVersions = PlayerSettings.Android.targetSdkVersion; if ((int)targetAndroidSdkVersions >= sdkConfig.recommendedAPILevel) { target_API_Level = true; allFixed &= target_API_Level; } else { target_API_Level = false; allFixed &= target_API_Level; } //脚本backend if (PlayerSettings.GetScriptingBackend(BuildTargetGroup.Android) == ScriptingImplementation.IL2CPP) { scripting_Backend = true; allFixed &= scripting_Backend; } else { scripting_Backend = false; allFixed &= scripting_Backend; } //cpu架构 if (PlayerSettings.Android.targetArchitectures == AndroidArchitecture.ARM64) { target_Architectures = true; allFixed &= target_Architectures; } else { target_Architectures = false; allFixed &= target_Architectures; } //是否允许unsafe代码 if (PlayerSettings.allowUnsafeCode) { allow_Unsafe_Code = true; allFixed &= allow_Unsafe_Code; } else { allow_Unsafe_Code = false; allFixed &= allow_Unsafe_Code; } //是否禁用MultiThreadedRendering if (PlayerSettings.GetMobileMTRendering(BuildTargetGroup.Android)) { disableMultiThreadedRendering = false; allFixed &= disableMultiThreadedRendering; } else { disableMultiThreadedRendering = true; allFixed &= disableMultiThreadedRendering; } #endregion CheckAllIssues_X1(); } #region 通用修复项 static void FixTags() { string[] tags = new string[] { "SpatialObject", "SpatialUI", "SpatialUI(NoInteractable)", "SpatialHandler" }; Object tagManagerObject = AssetDatabase.LoadAssetAtPath("ProjectSettings/TagManager.asset", typeof(Object)); if (tagManagerObject == null) { return; } SerializedObject tagManager = new SerializedObject(tagManagerObject); SerializedProperty tagsProp = tagManager.FindProperty("tags"); //Debug.Log("TagsPorp Size:" + tagsProp.arraySize); List tagsExists = new List(); for (int i = 0; i < tagsProp.arraySize; i++) { tagsExists.Add(tagsProp.GetArrayElementAtIndex(i).stringValue); } foreach (string tag in tags) { if (!tagsExists.Contains(tag)) { tagsExists.Add(tag); } } tagsProp.ClearArray(); foreach (string tag in tagsExists) { tagsProp.InsertArrayElementAtIndex(Mathf.Clamp(0, tagsProp.arraySize - 1, 128)); tagsProp.GetArrayElementAtIndex(tagsProp.arraySize - 1).stringValue = tag; } tagManager.ApplyModifiedProperties(); } static void FixTargetPlatform() { EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android); } static void FixClientServerMode() { if (sdkConfig.clientServerMode) { //向ScriptingDefineSymbols添加EZXRCS var symbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android); if (!symbols.Contains("EZXRCS")) { symbols += ";EZXRCS"; PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, symbols); } } else { //去掉ScriptingDefineSymbols中的EZXRCS,避免移除package的时候会因为引用丢失而报错 string symbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android); if (symbols.Contains("EZXRCS;")) { symbols = symbols.Replace("EZXRCS;", ""); PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, symbols); } else if (symbols.Contains("EZXRCS")) { symbols = symbols.Replace("EZXRCS", ""); PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, symbols); } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } static void FixGraphicsAPI() { PlayerSettings.SetUseDefaultGraphicsAPIs(BuildTarget.Android, false); PlayerSettings.SetGraphicsAPIs(BuildTarget.Android, new GraphicsDeviceType[] { GraphicsDeviceType.OpenGLES3 }); } static void FixMinimumAPILevel() { PlayerSettings.Android.minSdkVersion = (AndroidSdkVersions)sdkConfig.recommendedAPILevel; } static void FixTargetAPILevel() { PlayerSettings.Android.targetSdkVersion = (AndroidSdkVersions)sdkConfig.recommendedAPILevel; } static void FixScriptingBackend() { PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, ScriptingImplementation.IL2CPP); } static void FixTargetArchitectures() { PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64; } static void FixAllowUnsafeCode() { PlayerSettings.allowUnsafeCode = true; } static void FixMultiThreadedRendering() { PlayerSettings.SetMobileMTRendering(BuildTargetGroup.Android, false); } /// /// 将sdk所带的功能名配置到全局符号定义,主要用于类似XRMan这种会涉及到多模块的脚本做#if用 /// static void SetAbilitiesSymbols() { if (sdkConfig.spatialMesh) { AddSymbol("SpatialMesh"); } else { RemoveSymbol("SpatialMesh"); } if (sdkConfig.spatialComputing) { AddSymbol("SpatialComputing"); } else { RemoveSymbol("SpatialComputing"); } if (sdkConfig.imageTracking) { AddSymbol("Tracking2D"); } else { RemoveSymbol("Tracking2D"); } if (sdkConfig.objectDetection) { AddSymbol("Tracking3D"); } else { RemoveSymbol("Tracking3D"); } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } /// /// 向ScriptingDefineSymbols添加symbol /// /// static void AddSymbol(string symbol) { var symbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android); if (!symbols.Contains(symbol)) { symbols += ";" + symbol; PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, symbols); } } /// /// 从ScriptingDefineSymbols中去掉symbol /// /// static void RemoveSymbol(string symbol) { string symbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android); if (symbols.Contains(symbol + ";")) { symbols = symbols.Replace(symbol + ";", ""); PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, symbols); } else if (symbols.Contains(symbol)) { symbols = symbols.Replace(symbol, ""); PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, symbols); } } //Note: 这里每添加一条,都应该在下方的FixAllIssues中添加一行执行代码 #endregion static partial void Fix_X1(); public static void FixAllIssues() { Init(); #region 通用修复项 FixTags(); FixTargetPlatform(); FixClientServerMode(); FixGraphicsAPI(); FixMinimumAPILevel(); FixTargetAPILevel(); FixScriptingBackend(); FixTargetArchitectures(); FixAllowUnsafeCode(); FixMultiThreadedRendering(); SetAbilitiesSymbols(); #endregion Fix_X1(); } }