尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

PuerTS Unity il2cpp 优化特性全指南:原理、启用方式、代码生成模式与 iOS 构建排错

PuerTS Unity il2cpp 优化特性全指南:原理、启用方式、代码生成模式与 iOS 构建排错 PuerTS Unity il2cpp 优化特性全指南原理、启用方式、代码生成模式与 iOS 构建排错【免费下载链接】puertsPUER(普洱) Typescript. Lets write your game in UE or Unity with TypeScript.项目地址: https://gitcode.com/GitHub_Trending/pu/puerts适用版本PuerTS 2.0.0PuerTS 为 Unity 提供了一项名为il2cpp 优化xIl2cpp binding的专项能力在 il2cpp 构建环境下绕过传统 PInvoke 调用链通过 il2cpp 的InternalCall接口直接访问 C#从而大幅压低 JavaScript 与 C# 之间的跨语言调用开销。本文基于仓库 il2cpp 优化特性文档 展开结合unity/upms/core下的运行时与编辑器源码完整讲解该特性的实现原理、版本/平台启用矩阵、三种代码生成模式的选择与操作步骤、以及 iOS 构建中两个高频报错的解决方案并给出 性能数据 中的实测对比作为选型依据。读完本文你将能独立完成 il2cpp 优化特性的开启、胶水代码生成与真机构建排错。一、优化原理绕过 PInvoke直连 C#从概念上讲il2cpp 优化的核心思路是绕过 PInvoke改用 il2cpp 接口直接访问 C#从而减少跨语言调用时不必要的间接层与编组开销最终带来显著的性能提升。完整性能数据可参考 il2cpp 优化特性性能数据。在源码层面这一“绕过 PInvoke”的设计体现在两个关键点1. 编译宏开关决定运行时实现无论是运行时环境还是原生 API 声明il2cpp 优化路径都受同一组编译宏控制。以 ScriptEnv.cs 为例整个优化版运行时实现被包裹在#if !PUERTS_DISABLE_IL2CPP_OPTIMIZATION ENABLE_IL2CPP即仅在il2cpp 后端ENABLE_IL2CPP且未显式禁用优化!PUERTS_DISABLE_IL2CPP_OPTIMIZATION时才编译使用优化路径。这与文档中“通过 Unity Player Settings 添加 Scripting Define Symbol”的启用/禁用方式一一对应。2. 用InternalCall取代DllImport对比仓库中两套 Native API 声明可以发现本质差异常规 PInvoke 路径PInvoke/Native/PuertsDLL.cs 通过[DllImport(puerts)]从外部原生插件加载导出函数il2cpp 优化路径IL2Cpp/Native/NativeAPI.cs 中的关键接口改为[MethodImpl(MethodImplOptions.InternalCall)]声明让 il2cpp 在 AOT 编译阶段直接把调用接到对应的 C# 实现上不再经过 PInvoke 的查找与参数编组环节。同时优化路径下还引入了独立的 TypeRegister.cs使用RegisterInfoManager管理类型注册信息、ObjectPool.cs、ScriptObject.cs 等一整套配套实现与 PInvoke 路径形成两套平行的运行时。二、版本与平台矩阵如何启用 / 禁用该特性默认行为随版本演进而变化启用/禁用统一通过在 UnityPlayer Settings → Scripting Define Symbols中添加宏实现。从源码看PUERTS_DISABLE_IL2CPP_OPTIMIZATION与PUERTS_IL2CPP_OPTIMIZATION会直接影响上述#if编译分支的取舍。版本区间默认开启平台默认关闭平台关闭/开启方式≤ 2.1.1无全部平台默认关闭全部平台添加PUERTS_IL2CPP_OPTIMIZATION开启2.2.0 ~ 2.2.1Windows、macOS、Linux、AndroidiOS、WebGL已开启的平台添加PUERTS_DISABLE_IL2CPP_OPTIMIZATION关闭iOS/WebGL 添加PUERTS_IL2CPP_OPTIMIZATION开启≥ 2.2.2Windows、macOS、Linux、Android、WebGLiOS已开启的平台添加PUERTS_DISABLE_IL2CPP_OPTIMIZATION关闭iOS 添加PUERTS_IL2CPP_OPTIMIZATION开启几点使用提示宏仅影响编译期分支选择优化路径与 PInvoke 路径是两套并行实现见 IL2Cpp 与 PInvoke 目录切换宏后需要重新编译并重新生成对应胶水代码iOS 持续默认关闭是出于稳定性考虑若要在 iOS 上开启请务必配合下一节的代码生成步骤并留意文末的 iOS 构建 FAQ修改宏后建议清理一次生成代码再重新生成Unity 菜单Tools/PuerTS/Clear Generated Code避免旧产物干扰。三、使用步骤三种代码生成模式开启优化后还需要为需要暴露给 JS 的 C# 类型生成“胶水代码”。在 Unity 编辑器菜单Tools/PuerTS/Generate il2cpp/下提供三种模式按“性能 vs 代码体积”权衡选择菜单项定位特点Static Wrapper Mode追求更高性能全量生成静态包装器wrapper胶水代码调用路径最短、性能最好但生成的 C# 代码量最大Reflection Mode追求更小代码量仅生成基于反射的注册胶水体积小但调用经反射间接层性能略逊Minimal Bridge, Reflection Mode追求最小生成产物生成最精简的桥接代码 反射模式产物最小适合对包体敏感的场景源码视角三个菜单项做了什么三个菜单项的实现集中在 UnityMenu.cs本质都是调用CSharpFileExporter.GenAll(saveTo, ...)区别仅在于两个布尔参数// Reflection Mode无 wrapper纯反射 CSharpFileExporter.GenAll(saveTo, false, true); // Static Wrapper Mode生成静态 wrapper非反射 CSharpFileExporter.GenAll(saveTo, false, false); // Minimal Bridge, Reflection Mode最小桥接 反射 CSharpFileExporter.GenAll(saveTo, true, true);生成结果统一输出到PathHelper.GetIl2cppPluginPath()同时还会调用GenExtensionMethodInfos扩展方法信息与GenLinkXmllink.xml防止裁剪掉被反射/JS 引用的类型。StaticWrapperMenu中另一入口 GenerateStaticWrappersTo 则展示了静态包装器生成的完整流水线通过[Binding]特性收集需要绑定的类型来自 Configure 的GetConfigureByTags应用过滤器Filter支持(MemberInfo)与(FilterAction, MemberInfo)两种签名可针对单个成员返回BindingMode.DontBinding排除绑定加载扩展方法信息逐类型调用StaticWrapperGenerator.GenerateWrapperForType生成*.cs包装器文件汇总生成RegisterInfo_Gen.cs注册信息文件与扩展方法信息文件。因此你在[Configure]/[Binding]类里声明的绑定范围与 Filter直接决定生成胶水代码的规模。若生成时报 StaticWrapper 相关错误如某些成员无法静态包装可按 FAQHelper.cs 中的提示用 Filter 排除对应成员日志编号 Puer010。四、性能表现三种模式的实测对比为帮助选型仓库 性能数据文档 给出了 AndroidVivo Neo6SE与 iOSiPhone XsMax上的实测数据。测试口径说明Puer S未使用 il2cpp 优化 生成 StaticWrapperPuer X R使用 il2cpp 优化 Reflection 模式无 StaticWrapperPuer X S使用 il2cpp 优化 StaticWrapper 模式时间单位为毫秒ms数值越小越好关注结构体等跨语言调用时建议扣除 C# 侧 API 自身耗时csharp 列。AndroidVivo Neo6SEMethodStaticCallcsharpxLuapuer Spuer X Rpuer X Svoid Payload();×2000000.034.730.042.024.0void Payload();√2000000.021.323.020.09.0void Payload(int);√2000000.018.130.032.024.0void Payload(int);×2000000.037.036.056.029.0void Payload(int, int, float);√2000000.037.438.062.016.0void Payload(int, int, float);×2000000.056.432.068.016.0float Payload(int, int, float);√2000000.330.125.072.036.0float Payload(int, int, float);×2000000.341.430.095.025.0float Payload();√2000000.217.829.034.027.0float Payload();×2000000.238.333.059.014.0Quaternion Payload(Transform);√20000024.387.393.058.046.0Quaternion Payload(Transform);×20000024.2100.090.060.046.0Quaternion Payload(Transform, float, float, float);√20000043.1102.298.085.048.0Quaternion Payload(Transform, float, float, float);×20000043.0112.699.088.049.0Quaternion Payload(Transform, Vector3);√20000024.2103.7152.072.047.0Quaternion Payload(Transform, Vector3);×20000024.3118.3149.073.049.0fibonacci(40);√1640.820771.11899.01888.01887.0payload(): number // ScriptCallScript√200000000245.39350.3183.0182.0182.0iOSiPhone XsMaxMethodStaticCallcsharpxLuapuer Spuer X Rpuer X Svoid Payload();×2000000.010.228.027.024.0void Payload();√2000000.025.834.034.026.0void Payload(int);√2000000.010.727.030.022.0void Payload(int);×2000000.021.230.033.023.0void Payload(int, int, float);√2000000.012.334.047.026.0void Payload(int, int, float);×2000000.023.936.050.028.0float Payload(int, int, float);√2000000.010.443.072.034.0float Payload(int, int, float);×2000000.032.143.073.036.0float Payload();√2000000.311.029.046.025.0float Payload();×2000000.316.431.049.027.0Quaternion Payload(Transform);√20000034.068.799.072.062.0Quaternion Payload(Transform);×20000034.983.5100.074.067.0Quaternion Payload(Transform, float, float, float);√20000063.378.5108.0101.083.0Quaternion Payload(Transform, float, float, float);×20000063.689.7107.0102.075.0Quaternion Payload(Transform, Vector3);√20000035.978.8159.088.064.0Quaternion Payload(Transform, Vector3);×20000034.895.8168.088.069.0fibonacci(40);√1500.820580.617513.017315.017474.0payload(): number // ScriptCallScript√200000000282.39093.210896.010502.010851.0说明以上数据来自仓库性能文档因测试环境差异可能存在轻微误差文档同时提示关注 interop 性能尤其 struct 场景时建议减去 C# 侧 API 自身耗时。整体趋势是启用 il2cpp 优化后携带对象/结构体参数的调用如Quaternion Payload(Transform, Vector3)降幅最为明显且 Static Wrapper 模式通常优于 Reflection 模式而纯脚本自执行ScriptCallScript与无参调用受跨语言开销影响较小三种模式差距不大。五、常见问题FAQ1. iOS 构建报错 “hash_map header not found”该问题常见于 Unity 2021 及更早版本构建时部分 il2cpp 头文件没有被自动包含进 Xcode 工程输出。解决办法在 Unity 安装目录下找到缺失的头文件例如YourUnity.app/Contents/il2cpp/external/将缺失的头文件手动拷贝到 iOS 构建产物目录iosbuild/Libraries/external/下再重新构建。2. iOS 构建报错 “ReentrantLock is ambigious”该问题常见于 Unity 2022 系列版本原因是 il2cpp 基元库的命名空间内联方式与编译器冲突。解决方案是修改 Unity 安装目录下的 il2cpp 配置头文件路径按你的 Unity 安装位置调整/Applications/Unity/Hub/Editor/2022.3.47f1c1/PlaybackEngines/iOSSupport/il2cpp/libil2cpp/il2cpp-config.h在文件开头的#pragma once之后增加一行宏定义#pragma once #define BASELIB_INLINE_NAMESPACE il2cpp_baselib //this line fix ReentrantLock is ambigious #include string.h3. 构建期错误自动提示仓库内置了 FAQHelper.cs 构建监听会在构建日志中识别典型错误并输出带编号的引导日志[Puer010]StaticWrapper 生成错误可通过 Filter 排除部分成员[Puer011]RegisterInfo 错误建议先清理生成代码再重新生成[Puer012]缺少unityenv_for_puerts.h宏头文件导致构建失败提示使用菜单Tools/PuerTS/Generate il2cpp/macro.h对应 UnityMenu.cs 中的Advanced/Generate Native Plugin Files它会生成宏头文件并拷贝原生插件资源解决。六、小结il2cpp 优化是 PuerTS 在 Unity il2cpp 后端下的关键性能开关其本质是用InternalCall直连取代 PInvoke 间接调用并在编辑器侧以三种胶水代码生成模式提供“性能 / 体积”的灵活权衡。使用时请按版本对照第二节的平台矩阵配置宏按性能诉求选择第三节的生成模式并留意 iOS 平台的两个经典构建坑。相关实现与测试代码可在 IL2Cpp 运行时目录、生成器目录 以及 Javascript 跨语言测试用例 中进一步研读。【免费下载链接】puertsPUER(普洱) Typescript. Lets write your game in UE or Unity with TypeScript.项目地址: https://gitcode.com/GitHub_Trending/pu/puerts创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表