返回介绍

博客

帮助文档

代码裁剪

发布于 2024-08-03 14:42:57 字数 8395 浏览 0 评论 0 收藏 0

Unity使用了代码裁剪技术来帮助减少il2cpp backend的包体大小。如果未做防裁剪处理,由于AOT主工程里的代码一般不多,大量的C#类型和函数被 裁剪,导致热更新中调用这些被裁剪类或函数出现如下异常:

    // 类型缺失错误
    Unity: TypeLoadException: Could not load type 'Xxx' from assembly 'yyy'

    // 函数缺失错误
    MissingMethodException: xxxx

解决办法

根据日志错误日志确定哪个类型或函数被裁减,在link.xml里保留这个类型或函数,或者在主工程里显式地加上对这些类或函数的调用。 如果不熟悉如何在link.xml保留这个类型或函数,请参阅代码裁剪

但这种办法终究很麻烦,实际项目中有大量被裁剪的类型,你一遍遍地进行"打包-类型缺失-补充-打包"的操作, 浪费了太多时间。 com.code-philosophy.hybridclr 包提供了一个便捷的菜单命令HybridCLR/Generate/LinkXml, 能一键生成热更新工程里的所有AOT类型及函数引用。

:::caution 注意,如果你主工程中没有引用过某个程序集的任何代码,即使在link.xml中保留,该程序集也会被完全裁剪。因此对于每个要保留的AOT程序集, 请确保在主工程代码中显式引用过它的某个类或函数。 :::

AOT类型及函数预留

com.code-philosophy.hybridclr的HybridCLR/Generate/LinkXml命令虽然可以智能地扫描出你当前引用的AOT类型,却不能预知你未来将来使用的 类型。因此你仍然需要有规划地提前在 Assets/link.xml(注意!不是自动生成的那个link.xml)预留你将来 可能用到的类型。切记不要疏漏,免得出现上线后某次更新使用的类型被裁剪的尴尬状况!

检查热更新代码中是否引用了被裁剪的类型或函数

只要构建游戏时正确执行了HybridCLR/Generate/All,运行当时的热更新代码,不会出现类型或函数缺失的问题。但随着后面热更新代码不断迭代, 有可能访问了被裁剪的类型或函数。如果能提前在发布热更新代码时检查出来,可以及早发现和解决问题。

自v5.0.0版本起,提供HybridCLR.Editor.HotUpdate.MissingMetadataChecker类用于检查是否访问了被裁剪的类型和函数。示例代码如下:

        public static void CheckAccessMissingMetadata()
        {
            BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
            // aotDir指向 构建主包时生成的裁剪aot dll目录,而不是最新的SettingsUtil.GetAssembliesPostIl2CppStripDir(target)目录。
            // 一般来说,发布热更新包时,由于中间可能调用过generate/all,SettingsUtil.GetAssembliesPostIl2CppStripDir(target)目录中包含了最新的aot dll,
            // 肯定无法检查出类型或者函数裁剪的问题。
            // 需要在构建完主包后,将当时的aot dll保存下来,供后面补充元数据或者裁剪检查。
            string aotDir = "xxxx"; 

            // 第2个参数excludeDllNames为要排除的aot dll。一般取空列表即可。对于旗舰版本用户,
            // excludeDllNames需要为dhe程序集列表,因为dhe 程序集会进行热更新,热更新代码中
            // 引用的dhe程序集中的类型或函数肯定存在。
            var checker = new MissingMetadataChecker(aotDir, new List<string>());

            string hotUpdateDir = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target);
            foreach (var dll in SettingsUtil.HotUpdateAssemblyFilesExcludePreserved)
            {
                string dllPath = $"{hotUpdateDir}/{dll}";
                bool notAnyMissing = checker.Check(dllPath);
                if (!notAnyMissing)
                {
                    // DO SOMETHING
                }
            }
        }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文