UnityEditorunity

[Unity 3d] 编辑器程序集编译API - 笔记

2022-05-10  本文已影响0人  雨落随风

本文是个笔记,记录 2 个编辑器下编译程序集的逻辑。

一 . 编译 Runtime 用的程序集

Runtime 用的程序集:特征是会剔除 #if UNITY_EDITOR 注释的逻辑块)

  public static void OnAssemblyBuildRequired()
        {
            // todo 目前是全部都编译,有木有方法只编译需要的 程序集呢?
            var buildDir = Application.temporaryCachePath;
            var files = new DirectoryInfo(buildDir).GetFiles();
            foreach (var file in files)
            {
                FileUtil.DeleteFileOrDirectory(file.FullName);
            }
            
            var target = EditorUserBuildSettings.activeBuildTarget;
            var group = BuildPipeline.GetBuildTargetGroup(target);
            ScriptCompilationSettings scriptCompilationSettings = default;
            scriptCompilationSettings.group = group;
            scriptCompilationSettings.target = target;

            ScriptCompilationResult scriptCompilationResult = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, buildDir);
            var lib_dir = Path.Combine(Application.dataPath, "..", "Library\\ScriptAssemblies");
            foreach (var item in Instance.assemblies)
            {
                if (item.IsValid)    // 如果配置正确则尝试转存储文件
                {
                    var file = new FileInfo(Path.Combine(lib_dir, item.Dll));
                    var lastWriteTime = file.LastWriteTime.Ticks;
                    if (item.lastWriteTime < lastWriteTime)
                    {
                        item.lastWriteTime = lastWriteTime;
                        FileUtil.ReplaceFile(Path.Combine(buildDir, item.Dll), item.OutputPath);
                        item.UpdateInformation();
                    }
                }
                else
                {
                    Debug.LogError($"{nameof(AssemblyHotfixManager)}: 请先完善 Hotfix Configuration 配置项!");
                }
            }
            EditorUtility.SetDirty(Instance);
        }

二 . 编译指定 .asmdef 定义的程序集

   public static void SyncAssemblyRawData(bool forceCompilie = false)
    {       
           // 1.  dll 编译存放处
            var lib_dir = Path.Combine(Application.dataPath, "..", "Library\\ScriptAssemblies");
            foreach (var item in Instance.assemblies)
            {
                // 如果配置正确则开始尝试编译
                if (item.IsValid)
                {
                    var data = JsonUtility.FromJson<SimplifiedAssemblyData>(item.assembly.text);
                    var dll = Path.Combine(lib_dir, $"{data.name}.dll");
                    var temp = Path.Combine(Application.temporaryCachePath, $"{data.name}.bytes");
                    var file = new FileInfo(dll);
                    if (file.Exists)
                    {
                        var lastWriteTime = file.LastWriteTime.Ticks;
                        if (forceCompilie || item.lastWriteTime < lastWriteTime)
                        {
                            item.lastWriteTime = lastWriteTime;
                            var assembly = CompilationPipeline.GetAssemblies(AssembliesType.Player).FirstOrDefault(v => v.name == item.assembly.name);
                            if (null != assembly)
                            {
                                // Compiles scripts outside the Assets folder into a managed assembly that can be used inside the Assets folder.
                                AssemblyBuilder builder = new AssemblyBuilder(temp, assembly.sourceFiles);
                                builder.compilerOptions.AllowUnsafeCode = item.AllowUnsafeCode;
                                BuildTargetGroup buildTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
                                builder.compilerOptions.ApiCompatibilityLevel = PlayerSettings.GetApiCompatibilityLevel(buildTargetGroup);
                                builder.additionalReferences = assembly.allReferences;
                                builder.flags = AssemblyBuilderFlags.None;
                                // todo: 以下动作会导致程序集完成编译后IDE 报错,待确认:减少编译频率,变成 aa build 时编译,同时看能不能将 csproj 回到原点
                                builder.referencesOptions = ReferencesOptions.UseEngineModules;
                                builder.buildTarget = EditorUserBuildSettings.activeBuildTarget;
                                builder.buildTargetGroup = buildTargetGroup;
                                builder.excludeReferences = new string[] { assembly.outputPath };
                                builder.additionalDefines = assembly.defines;
                                builder.compilerOptions = assembly.compilerOptions;
                                builder.buildFinished += (arg1, arg2) =>
                                {
                                    bool noErr = true;
                                    foreach (var msg in arg2)
                                    {
                                        if (msg.type == CompilerMessageType.Error)
                                        {
                                            Debug.LogError(msg.message);
                                            noErr = false;
                                        }
                                        else if (msg.type == CompilerMessageType.Warning)
                                        {
                                            Debug.LogWarning(msg.message);
                                        }
                                        else
                                        {
                                            Debug.Log(msg.message);
                                        }
                                    }
                                    if (noErr)
                                    {
                                        FileUtil.ReplaceFile(temp, item.OutputPath);
                                        item.UpdateInformation();
                                    }

                                };
                                if (!builder.Build())
                                {
                                    Debug.LogError($"{nameof(AssemblyHotfixManager)}: Assembly {item.Dll} Build Fail!");
                                }
                                else
                                {
                                    Debug.Log($"{nameof(AssemblyHotfixManager)} 热更程序集: <color=yellow>{item.Dll} </color> 完成构建!");
                                }
                            }
                        }
                    }
                }
                else
                {
                    Debug.LogError($"{nameof(AssemblyHotfixManager)}: 请先完善 Hotfix Configuration 配置项!");
                }
                EditorUtility.SetDirty(Instance);
                AssetDatabase.Refresh();
            }
        }

总结说明:

  1. 用 Assembly Definition File 定义的程序集在 Unity 中会编译成编辑器下使用的 dll 和 打包后使用的 dll 这 2种情况,编辑器环境加载的多为第一种,后者则是在用户 Build app 或者可寻址 build 时才会触发构建。
  2. 这两种情况的程序集,在 Unity 内部的概念种分别叫:EditorAssemblies 、PlayerAssembles;
  3. 这俩程序集最大特点是宏 #if UNITY_EDITOR 包裹的逻辑是否被剔除,以及是否引使用了 EngineModules.
  4. 按照自己的理解,有朋友会将 PlayerAssemblies 说成"Runtime 用的 dll ",或者说成 “Release 版本的 dll ”,虽五花八门,但经得起推敲哈。
  5. 当然,可以自己使用 Roslyn 编译哈,别问,问就是可行,我朋友试过了~
上一篇 下一篇

猜你喜欢

热点阅读