Unity打包Windows遇CS0103错误:EditorUtility与AssetDatabase不存在
解决Unity打包Windows版本时EditorUtility和AssetDatabase不存在的错误
问题背景
开发面向牙医的Unity 3D牙齿移动项目,核心功能包括:
- 导入含牙齿位置的CSV文件并复制到项目文件夹
- 点击「Next Week」按钮保存牙齿新位置为
Week + n格式CSV,读取最新CSV用于后续操作 - 点击「Save and Export」导出STL文件
打包Windows版本时出现以下编译错误:
UnityEditor.BuildPlayerWindow+BuildMethodException: 4 errors at UnityEditor.BuildPlayerWindow+DefaultBuildMethods.BuildPlayer (UnityEditor.BuildPlayerOptions options) [0x002da] in :0 at UnityEditor.BuildPlayerWindow.CallBuildMethods (System.Boolean askForBuildLocation, UnityEditor.BuildOptions defaultBuildOptions) [0x00080] in :0 UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&) error CS0103: The name 'EditorUtility' does not exist in the current context error CS0103: The name 'AssetDatabase' does not exist in the current context Build completed with a result of 'Failed' in 3 seconds (2931 ms) UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
错误原因
EditorUtility和AssetDatabase属于UnityEditor命名空间,仅在Unity编辑器环境中可用,打包后的运行时程序不包含该命名空间的API,因此编译时会提示名称不存在。
解决方案
1. 隔离编辑器专属代码
用#if UNITY_EDITOR和#endif条件编译指令包裹仅在编辑器中运行的代码,确保打包时编译器忽略这部分代码。
2. 替换运行时资源加载逻辑
运行时不能使用AssetDatabase.LoadAssetAtPath,改用System.IO直接读取文件内容,或使用Resources.Load(需确保文件在Resources文件夹下并正确打包)。
3. 移除运行时不必要的AssetDatabase操作
打包后的程序无需调用AssetDatabase.Refresh(),该操作仅用于编辑器中刷新资源列表。
修改后的代码示例
修改SubmitManager.cs
using UnityEngine.UI; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; using CsvManagement; using System.IO; namespace Submit { public class SubmitManager : MonoBehaviour { public GameObject teeth; public CsvExampleObjectSpawner csv; // 直接引用场景实例,不要new public static int countweek; public static string filename; public void submit() { if(CsvExampleObjectSpawner.next == 1) { countweek = countweek + 1; filename = "week"+countweek+".csv"; csv.wirteCSV(filename); // 仅编辑器环境刷新资源库 #if UNITY_EDITOR UnityEditor.AssetDatabase.Refresh(); #endif StartCoroutine(NextScenes()); } else { Debug.Log("Please select file"); } } IEnumerator NextScenes() { yield return new WaitForSeconds(0.5f); SceneManager.LoadScene("Scene2"); } } }
修改CsvExampleObjectSpawner.cs
using System.Collections; using System.Collections.Generic; using UnityEngine; using LINQtoCSV; using System.IO; using System.Linq; using UnityEngine.UI; namespace CsvManagement { public class CsvExampleObjectSpawner : MonoBehaviour { private Dictionary<string, GameObject> prefabs = new Dictionary<string, GameObject>(); public GameObject[] objects; public GameObject myGameObjects; public TextAsset sceneDescriptor; string sourcePath; public static string filename; public Text FileName; public static Stack<string> stackOfFiles = new Stack<string>(); public static int next; public List<CsvSceneObject> posOfTeeth = new List<CsvSceneObject>(); void Awake() { foreach(var obj in objects) { prefabs[obj.name] = obj; } } public void OpenFileExplorer() { #if UNITY_EDITOR sourcePath = UnityEditor.EditorUtility.OpenFilePanel("Select the CSV file", "", "csv"); #else // 运行时替换为自定义文件选择逻辑,例如: // var dialog = new System.Windows.Forms.OpenFileDialog(); // dialog.Filter = "CSV Files (*.csv)|*.csv"; // if(dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK) // { // sourcePath = dialog.FileName; // } #endif if (!string.IsNullOrEmpty(sourcePath)) { filename = Path.GetFileName(sourcePath); FileName.text = "File Name : " +filename; CheckEmptyFolderAndAddFile(); next = 1; } else { if(stackOfFiles == null || stackOfFiles.Count == 0) { next = 0; } else { Debug.Log("The user unselected the file."); } } } public void CheckEmptyFolderAndAddFile() { string path = Application.dataPath + "/Resources/"; if (Directory.GetFiles(path).Length == 0 && Directory.GetDirectories(path).Length == 0) { Debug.Log("Directory is empty."); loadCSV(); readCSV(filename); stackOfFiles.Push(filename); } else { foreach (string file in Directory.GetFiles(path)) { File.Delete(file); } loadCSV(); readCSV(filename); stackOfFiles.Push(filename); } } public void loadCSV() { string backupPath = Application.dataPath + "/Resources/"; File.Copy(sourcePath, Path.Combine(backupPath, filename)); } public void readCSV(string filename) { // 运行时直接读取文件内容,无需通过AssetDatabase string filePath = Path.Combine(Application.dataPath, "Resources", filename); string csvContent = File.ReadAllText(filePath); CsvFileDescription inputFileDescription = new CsvFileDescription { SeparatorChar = ',', FirstLineHasColumnNames = true }; using (var ms = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(csvContent))) { using (var txtReader = new StreamReader(ms)) { CsvContext cc = new CsvContext(); cc.Read<CsvSceneObject>(txtReader, inputFileDescription) .ToList() .ForEach( so => { if(prefabs.TryGetValue(so.PrefabName, out var toothObj)) { toothObj.transform.position = new Vector3(so.X, so.Y, so.Z); toothObj.transform.rotation = Quaternion.Euler(so.RoX, so.RoY, so.RoZ); } }); } } } public void wirteCSV(string filename) { // 运行时使用持久化路径存储文件,避免权限问题 string pathOfFile = Path.Combine(Application.persistentDataPath, "CsvWeek", filename); Directory.CreateDirectory(Path.GetDirectoryName(pathOfFile)); posOfTeeth.Clear(); for(int i = 0; i < objects.Length; i++) { posOfTeeth.Add( new CsvSceneObject { PrefabName = objects[i].name.ToString(), X = objects[i].transform.position.x, Y = objects[i].transform.position.y, Z = objects[i].transform.position.z, RoX = objects[i].transform.rotation.eulerAngles.x, RoY = objects[i].transform.rotation.eulerAngles.y, RoZ = objects[i].transform.rotation.eulerAngles.z } ); } CsvFileDescription outputFileDescription = new CsvFileDescription { SeparatorChar = ',', FirstLineHasColumnNames = true, }; CsvContext cc = new CsvContext(); cc.Write<CsvSceneObject>(posOfTeeth, pathOfFile, outputFileDescription); Debug.Log($"Successfully wrote the file to: {pathOfFile}"); } // 确保CSV映射类已正确定义 public class CsvSceneObject { [CsvColumn(Name = "PrefabName")] public string PrefabName { get; set; } [CsvColumn(Name = "X")] public float X { get; set; } [CsvColumn(Name = "Y")] public float Y { get; set; } [CsvColumn(Name = "Z")] public float Z { get; set; } [CsvColumn(Name = "RoX")] public float RoX { get; set; } [CsvColumn(Name = "RoY")] public float RoY { get; set; } [CsvColumn(Name = "RoZ")] public float RoZ { get; set; } } } }
额外注意事项
- 运行时文件路径:避免直接读写
Assets文件夹,打包后该路径不存在,改用Application.persistentDataPath存储用户生成的文件。 - 文件选择:运行时无法使用
EditorUtility.OpenFilePanel,需替换为适合运行时的文件选择方案,比如Windows平台可引用System.Windows.Forms或使用Unity内置的文件对话框(Unity 2020+支持)。 - 资源加载:如果需要在运行时加载CSV作为TextAsset,需确保文件在
Resources文件夹下,打包前已正确导入,使用Resources.Load<TextAsset>(filenameWithoutExtension)加载。
内容的提问来源于stack exchange,提问作者Supreeya Kokheng
相关产品推荐
相关产品推荐

