包含此页的版本:
不含此页的版本:
使用以下信息来帮助找到在 iOS 设备上运行 Unity 应用程序时常见崩溃和其他问题的解决方案。
注意:如果排查问题后问题仍然存在,请参阅报告 iOS 的崩溃错误。
以下列表提供了此问题的一些常见原因:
List<int>,List<SomeStruct>,List<SomeEnum>用于序列化脚本属性。来自 Xcode 调试器控制台的信息通常可以帮助检测这些问题。从“查看”>“调试区域”>“激活控制台”访问调试器控制台。
当您的应用程序收到NullReferenceException.使用本机堆栈跟踪来找出故障发生的位置。
本机堆栈跟踪是故障调查的有用工具,但使用它们需要一些专业知识。发生这些硬件内存访问故障后,您通常无法继续。要访问本机堆栈跟踪,请键入bt all到 Xcode 调试器控制台中。检查打印的堆栈跟踪,因为它们可能包含有关错误发生位置的信息。例如,典型的堆栈跟踪可能如下所示:
...
Thread 1 (thread 11523):
1. 0 0x006267d0 in m_OptionsMenu_Start ()
1. 1 0x002e4160 in wrapper_runtime_invoke_object_runtime_invoke_void__this___object_intptr_intptr_intptr ()
1. 2 0x00a1dd64 in mono_jit_runtime_invoke (method=0x18b63bc, obj=0x5d10cb0, params=0x0, exc=0x2fffdd34) at /Users/mantasp/work/unity/unity-mono/External/Mono/mono/mono/mini/mini.c:4487
1. 3 0x0088481c in MonoBehaviour::InvokeMethodOrCoroutineChecked ()
...
找到“线程 1”的堆栈跟踪,这是主线程。堆栈跟踪的初始行将指向发生错误的位置。在此示例中,跟踪指示NullReferenceException发生在_OptionsMenu_脚本的_Start_方法。检查此方法实现有助于揭示问题的原因。通常,NullReferenceExceptions 发生在_Start_方法,当对初始化顺序做出不正确的假设时。
有时,调试器控制台中仅显示部分堆栈跟踪。例如:
Thread 1 (thread 11523):
1. 0 0x0062564c in start ()
此消息指示在应用程序的发布生成期间剥离了本机符号。若要进一步调查,请使用以下步骤访问全栈跟踪:
您可能会遇到类似Program received signal: "0".此警告消息通常不是致命的,表明 iOS 内存不足。通常,邮件等后台进程会释放一些内存,并且您的应用程序可以继续运行。但是,如果您的应用程序继续使用内存或要求更多内存,iOS 将开始终止包括您自己的应用程序在内的应用程序。Apple 没有记录哪些内存使用是安全的,但观察表明,使用少于 50% 的设备 RAM 的应用程序不存在重大内存使用问题。
要使用的主要指标是应用程序使用了多少 RAM。应用程序内存使用情况由以下组件组成:
| 元件 | 描述 |
|---|---|
| 应用程序代码 | 作系统需要将应用程序代码加载并保存在 RAM 中,但如果需要,其中一些代码可能会被丢弃。 |
| 本机堆 | 引擎用于将其状态和资产存储在RAM中。 |
| 托管堆 | 由您的il2cppUnity 开发的脚本后端,在为某些平台构建项目时,您可以将其用作 Mono 的替代品。更多信息 请参阅术语表运行时来存储 C# 对象。 |
| 金属内存池 | 用于存储纹理、帧缓冲区和编译的纹理着色器在 GPU 上运行的程序。更多信息 请参阅术语表. |
您可以在 Xcode 中跟踪应用程序内存使用情况。有关更多信息,请参阅收集有关内存使用的信息 (Apple Developer)。
若要保持较低的内存使用率,请使用以下建议:
向作系统查询可用内存量似乎是评估应用程序性能的最有效方法。但是,由于作系统使用大量动态缓冲区和缓存,因此可用内存统计数据可能不可靠。建议跟踪应用程序的内存消耗并将其用作主要指标,并结合 Xcode 内存工具,尤其是在加载新的场景场景包含游戏的环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍物和装饰品,基本上是将你的游戏设计和构建成碎片。更多信息
请参阅术语表.
建议检查设备日志以获取更多详细信息。为此,请使用以下步骤:
您可能还需要调查崩溃报告。有关详细信息,请参阅获取崩溃报告和诊断日志 (Apple Developer)。
有一个设置的时间限制,允许 iOS 应用程序呈现第一帧并处理输入。如果您的应用程序超过此限制,则 SpringBoard 将终止它。例如,在第一个场景的大小过大的应用程序中,可能会发生这种情况。建议创建一个带有初始屏幕的小型初始场景,等待几帧,然后继续加载较大的场景。为此,请使用以下示例:
IEnumerator Start() {
yield return new WaitForEndOfFrame();
// Do not forget using UnityEngine.SceneManagement directive
SceneManager.LoadScene("Test");
}
.NET 加密服务与托管代码剥离不兼容。这些服务依赖于反射,而托管代码剥离涉及静态代码分析。剥离工艺可以通过添加自定义link.xml文件到Assets文件夹。这指定了要从剥离中排除的类型和命名空间。排除System.Security.Crypography命名空间,以帮助解决此问题。例如,将以下内容添加到link.xml文件:
<linker>
<assembly fullname="mscorlib">
<namespace fullname="System.Security.Cryptography" preserve="all"/>
</assembly>
</linker>
您可以按照上一节中概述的相同方式解决此问题,也可以向脚本代码添加对特定类的额外引用。为此,请使用以下示例:
object obj = new MD5CryptoServiceProvider();
UI 中的某些作将导致 iOS 立即重新绘制窗口。最常见的示例是将带有 UIViewController 的 UIView 添加到主 UIWindow。如果从脚本调用本机函数,它将发生在 Unity 的 PlayerLoop 中,从而导致递归调用 PlayerLoop。发生这种情况时,您将收到错误消息PlayerLoop called recursively!.在这种情况下,请考虑将 performSelectorOnMainThread (Apple Developer) 方法waitUntilDone设置为 false。它将通知 iOS 安排作在 Unity 的 PlayerLoop 调用之间运行。
若要诊断此问题,请使用以下建议:
225.0.0.222在 UDP 端口上54997.检查您的网络设置是否允许此流量。分析器还将连接到范围内端口上的远程设备55000 - 55511从设备获取分析器数据。这些端口需要打开才能进行 TCP 访问。当构建的机器代码太大并达到 Xcode 限制时,会导致此问题。如果有很多脚本代码,或者在生成中使用大型外部 .NET 程序集,则可能会发生这种情况。使用脚本调试构建设置也会加剧此问题,因为它会为每个函数创建额外的指令。
为了帮助解决此问题,请在 Unity 编辑器中导航到 Edit > Project Settings > Player > iOS,然后尝试以下一个或多个选项:
如果问题仍然存在,建议将用户脚本代码拆分为多个程序集。例如,Plugins文件夹可用于放置任何拆分代码,因为此位置的代码将添加到其他程序集。还建议参考特殊文件夹和脚本编译顺序,了解有关特殊文件夹名称如何影响脚本编译的信息。
从 Xcode 版本 14.3 开始,Apple 引入了目标架构选项。借助目标架构,您可以在基于 ARM 的 Mac 上使用 iOS 模拟器,而无需在 Rosetta 模拟器模式下运行 Xcode。
要查看 iOS 模拟器,请使用以下步骤: