Unity 打包il2cpp模式时的常见问题分析

 Unity 编辑器模式下是采用.net 虚拟机解释执行.net 代码,发布的时候有两种模式,一种是mono虚拟机模式,一种是il2cpp模式。

由于iOS AppStore规定不允许使用虚拟机,所以发布到iOS,Unity采用了il2cpp技术,把IL(.net字节码) 的代码转成c++代码,然后再用xcode来进行编译。

发布到Android的时候,可以用mono与il2cpp模式,il2cpp由于转成native code直接在硬件CPU上跑,性能要比虚拟机解释执行要高,所以发布Android的时候我们也采用il2cpp。

但是开发者会遇到一些问题mono模式下能正常运行,编译il2cpp模式下会出现问题,如闪退等,本文将il2cpp 打包发布可能遇到的问题,进行分类,分析与总结,希望能给大家提供解决思路与方向。

  

il2cpp模式编译错误

  首先遇到的问题是使用il2cpp模式下编译C++代码报错。由于Android/iOS不同的版本对编译器(NDK/xcode)的版本要求也是不同的,而大多数同学下载的NDK/xcode 是网络上的一个版本,不一定匹配上unity 编译Android/iOS时对应的版本,所以如果在发布il2cpp模式过程中,当我们遇到编译错误的时候,首先先编译空项目,看看是不是NDK,SDK,xcode的版本不匹配导致的。

Unity Hub 现在也集成了一个功能就是安装对应Unity版本对应的NDK与SDK。安装正确的工具链编译问题一般能很轻松的解决。(如下图所示, Unity hub中不同unity版本,安装相关编译工具时的模块化安装)

Mono模式下没问题, il2cpp模式下报类型缺失错误

  开发完打包的时候,mono模式下没有问题, il2cpp模式下编译通过,但是运行的时候报”类型缺失的错误”。这也是常见的il2cpp模式下遇到的问题。C++是属于根据依赖进行编译的模式。Il2cpp中,如果我们编写的c#代码没有使用这个类,那么编译完C++代码后,这个类的二进制代码就不会出现在c++的代码中,运行的时候就会导致类型缺失,功能不正常等相关报错。

很多同学看到这里就有一个疑问,既然IL的.dll代码里面没有,为何C++的代码会调用呢?给大家举个例子你瞬间就明白了,假设有个资源预制体挂了一个组件,而这个组件只在资源上使用,代码中没有使用,编辑器模式下与mono模式下都能正常运行。而打包il2cpp的时候由于这个组件在代码中没有使用, 所以导致IL code中没有依赖,因此就不会被il2cpp打入进去,导致l2cpp模式下运行的时候类型缺失报错,功能不能正常使用。

了解了出错的原因与原理,解决方案就非常简单在ilcode代码里面加上组件类的代码引用与依赖就可以了,让il2cpp将相关的类与组件打入进去。比如动画的timeline等。

Mono模式没有问题,IL2CPP模式下闪退

  最后一类问题就是mono模式下没有问题,il2cpp模式下闪退。闪退其实就是手机app的这个进程由于运行时候的错误,OS必须要杀掉这个进程,而虚拟机解释执行式模式,不容易闪退,因为有虚拟机这一层作为保护隔绝,而对于il2cpp而言,全部已经转成了native 代码,如果运行的时候数据不对,比如除0异常,空指针等会导致OS 直接把进程删掉造成闪退。所以这样就会导致mono模式下不闪退,而il2cpp模式下却直接闪退。

  引起这类问题原因有很多,比如上面的类型缺失,可能导致闪退, 还有就是某个代码与数据跑出来缺失异常了,但是mono下由于有虚拟机的保护作用,异常可能被直接忽视了,导致我们认为还在app正常运行,而il2cpp模式下由于没有虚拟机的保护,可能直接被OS 杀掉。

  一般解决这类我们问题我们还是要通过隔离的手段,找出运行出错的代码与相关数据,然后分析原因来修正它。而不要老想着 “mono正常,而il2cpp模式下报错,闪退”是不是il2cpp的环境问题。其实很大一部分确实是我们的代码或我们代码跑的数据异常导致的。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Unity 中,可以使用 BuildPipeline.BuildPlayer 方法来实现一键打包。而编译 il2cpp 则需要使用 UnityIL2CPP 构建选项。 以下是一个简单的示例代码,演示了如何实现一键打包并编译 il2cpp: ```csharp using UnityEditor; using UnityEditor.Build.Reporting; using UnityEngine; public class BuildScript : MonoBehaviour { [MenuItem("Build/Build and Compile il2cpp")] public static void BuildAndCompile() { // 设置打包参数 string[] scenes = { "Assets/Scenes/MyScene.unity" }; string outputPath = "Builds/MyGame.exe"; BuildPlayerOptions buildOptions = new BuildPlayerOptions(); buildOptions.scenes = scenes; buildOptions.locationPathName = outputPath; buildOptions.target = BuildTarget.StandaloneWindows64; buildOptions.options = BuildOptions.None; // 打包 BuildReport buildReport = BuildPipeline.BuildPlayer(buildOptions); // 检查打包结果 if (buildReport.summary.result == BuildResult.Succeeded) { // 编译 il2cpp PlayerSettings.SetScriptingBackend(BuildTargetGroup.Standalone, ScriptingImplementation.IL2CPP); PlayerSettings.SetIl2CppCompilerConfiguration(BuildTargetGroup.Standalone, Il2CppCompilerConfiguration.Release); PlayerSettings.SetArchitecture(BuildTargetGroup.Standalone, 2); BuildPipeline.BuildPlayer(buildOptions); Debug.Log("Build and il2cpp compile succeeded!"); } else { Debug.LogError("Build failed!"); } } } ``` 在上面的代码中,我们在菜单栏中添加了一个 "Build/Build and Compile il2cpp" 的选项,当用户点击此选项,会执行 BuildAndCompile 方法。该方法首先使用 BuildPipeline.BuildPlayer 方法进行打包,然后检查打包结果。如果打包成功,则设置编译 il2cpp 所需的参数,并再次调用 BuildPipeline.BuildPlayer 方法进行编译。 需要注意的是,IL2CPP 编译可能需要一定的间,具体取决于项目的规模和复杂度。因此,建议用户在执行一键打包并编译 il2cpp 之前,先备份项目以防止意外情况发生。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值