Есть некоторые ситуации с iOSмобильной операционной системой Apple. Подробнее
Посмотрите в Словарь, где ваше приложение отлично работает в редакторе Unity, но не работает. не работает и не запускается на устройстве. Проблемы часто связаны с кодом или качеством контента. В этом разделе описаны наиболее распространенные сценарии.
Игра перестает отвечать на запросы через некоторое время. Xcode показывает «прервано» в строке состояния.
Это может произойти по ряду причин. Типичные причины включают:
- Ошибки сценария, такие как использование неинициализированных переменных и т. п.
- Использование сторонних библиотек, скомпилированных с помощью Thumb. Такие библиотеки вызывают известную проблему в компоновщике iOS SDK и могут вызывать случайные сбои.
- Использование универсальных типов со значениями в качестве параметров (например, List
, List , List ) для сериализуемых свойств скрипта. - Использование отражения при включенном удалении управляемого кода.
- Ошибки в нативном интерфейсе подключаемого модуля (сигнатура метода управляемого кода не соответствует сигнатуре функции нативного кода). Информация из консоли XCode Debugger часто может помочь обнаружить эти проблемы (меню Xcode: Вид > Область отладки > Активировать консоль).
Консоль Xcode показывает «Программа получила сигнал: ошибка «SIGBUS» или EXC_BAD_ACCESS.
Это сообщение обычно появляется на устройствах iOS, когда ваше приложение получает исключение NullReferenceException. Есть два способа выяснить, где произошла ошибка:
Управляемая трассировка стека
В Unity предусмотрена программная обработка исключения NullReferenceException. Компилятор AOT включает быструю проверку нулевых ссылок при каждом доступе к методу или переменной объекта. Эта функция влияет на производительность скрипта, поэтому она включена только для сборок для разработкиСборка для разработки включает символы отладки и включает профилировщик. Подробнее
См. в Словарь (включите параметр отладка скрипта в диалоговом окне Настройки сборки).
Если все было сделано правильно и ошибка действительно возникает в коде .NET, вы больше не увидите EXC_BAD_ACCESS. Вместо этого текст исключения .NET будет напечатан в консоли Xcode (иначе ваш код просто обработает его в операторе «catch»). Типичный вывод может быть таким:
Unhandled Exception: System.NullReferenceException: A null value was found where an object instance was required.
at DayController+$handleTimeOfDay$121+$.MoveNext () [0x0035a] in DayController.js:122
Это указывает на то, что ошибка произошла в методе handleTimeOfDay класса DayController, который работает как сопрограмма. Кроме того, если это код скрипта, вам обычно сообщают точный номер строки (например, «DayController.js:122»). Оскорбительная строка может выглядеть примерно так:
Instantiate(_imgwww.assetBundle.mainAsset);
Это может произойти, если, скажем, скрипт обращается к набору ресурсов без предварительной проверки правильности его загрузки.
Встроенная трассировка стека
Собственная трассировка стека — гораздо более мощный инструмент для исследования сбоев, но для ее использования требуется определенный опыт. Кроме того, как правило, вы не можете продолжать работу после возникновения этих собственных ошибок (аппаратного доступа к памяти). Чтобы получить собственную трассировку стека, введите 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 произошло внутри метода Start скрипта OptionsMenu. Если внимательно посмотреть на реализацию этого метода, можно выявить причину проблемы. Обычно исключения NullReferenceException возникают внутри метода Start, когда делаются неправильные предположения о порядке инициализации. В некоторых случаях в консоли отладчика отображается только частичная трассировка стека:
Thread 1 (thread 11523):
1. 0 0x0062564c in start ()
Это указывает на то, что собственные символы были удалены во время сборки выпуска приложения. Полную трассировку стека можно получить с помощью следующей процедуры:
- Удалить приложение с устройства.
- Очистить все цели.
- Создайте и запустите.
- Снова получите трассировку стека, как описано выше.
EXC_BAD_ACCESS возникает, когда внешняя библиотека связана с приложением Unity iOS.
Обычно это происходит, когда внешняя библиотека компилируется с набором инструкций ARM Thumb. В настоящее время такие библиотеки несовместимы с Unity. Проблема может быть легко решена путем перекомпиляции библиотеки без инструкций Thumb. Вы можете сделать это для проекта библиотеки Xcode, выполнив следующие действия:
- В Xcode выберите в меню Просмотр > Навигаторы > Показать навигатор проекта.
- Выберите проект Unity-iPhone, активируйте вкладку Настройки сборки
- В поле поиска введите: Другие флаги C
- Добавьте туда флаг -mno-thumb и пересоберите библиотеку.
Если исходный код библиотеки недоступен, вам следует запросить у поставщика версию библиотеки без большого пальца.
Консоль Xcode показывает «ПРЕДУПРЕЖДЕНИЕ -> applicationDidReceiveMemoryWarning()», и сразу после этого происходит сбой приложения
Иногда вы можете увидеть сообщение типа Программа получена: «0». Это предупреждающее сообщение часто не является фатальным и просто указывает, что iOS не хватает памяти и просит приложения освободить часть памяти. Как правило, фоновые процессы, такие как Mail, освобождают часть памяти, и ваше приложение может продолжать работать. Однако, если ваше приложение продолжает использовать память или запрашивать больше, ОС в конечном итоге начнет убивать приложения, и ваше может быть одним из них. Apple не документирует, какое использование памяти является безопасным, но эмпирические наблюдения показывают, что приложения, использующие менее 50% всей оперативной памяти устройства, не имеют серьезных проблем с использованием памяти. Основная метрика, на которую следует полагаться, — это объем оперативной памяти, используемой вашим приложением. Использование памяти вашим приложением состоит из трех основных компонентов:
- Код приложения (ОС должна загружать код приложения и хранить его в ОЗУ, но при необходимости часть кода может быть удалена)
- Собственная куча (используемая движком для хранения своего состояния, ресурсов и т. д. в ОЗУ)
- Управляемая куча (используется средой выполнения Mono для хранения объектов C#)
- Пулы памяти драйвера GLES: текстуры, буферы кадра, скомпилированные шейдерыПрограмма, работающая на графическом процессоре. Подробнее
См. в Словарь и т. д. Использование памяти вашим приложением можно отслеживать с помощью двух инструментов Xcode Instruments: Мониторинг активности и Выделения. Вы можете начать с меню запуска Xcode: Продукт > Профиль, а затем выбрать конкретный инструмент или через Xcode > Открыть инструменты разработчика > Инструменты. Инструмент Activity Monitor показывает всю статистику процесса, включая Реальную память, которую можно рассматривать как общий объем оперативной памяти, используемой вашим приложением. Примечание. Комбинация версии ОС и аппаратного обеспечения устройства может заметно повлиять на показатели использования памяти, поэтому следует соблюдать осторожность при сравнении показателей, полученных на разных устройствах.
Примечание. внутренний профилировщик показывает только кучу, выделенную .NET скриптыЧасть кода, позволяющая создавать собственные Компоненты, запускать игровые события, изменять свойства Компонентов с течением времени и реагировать на действия пользователя любым удобным для вас способом. Подробнее
См. в Словарь. Общее использование памяти можно определить с помощью инструментов Xcode, как показано выше. Этот рисунок включает в себя части двоичного файла приложения, некоторые стандартные буферы фреймворка, внутренние буферы состояния движка Unity, динамическую кучу .NET (число, напечатанное внутренним профилировщиком), динамическую кучу драйвера GLES и некоторые другие разные вещи.
Другой инструмент отображает все выделения, сделанные вашим приложением, и включает статистику как собственной кучи, так и управляемой кучи. Важной статистикой является значение Чистые байты.
Чтобы снизить использование памяти:
- Уменьшите размер двоичного файла приложения, используя самые надежные параметры разделения iOS, и избегайте ненужных зависимостейв контексте диспетчера пакетов , зависимость — это конкретная версия пакета (выраженная в форме
имя_пакета@версия_пакета
), которая требуется проекту или другому пакету для работы. Проекты и пакеты используют атрибут dependencies в своих манифестах для определения набора требуемых пакетов. Для проектов это считается прямой зависимостью; для пакетов это косвенные или транзитивные зависимости. Подробнее
См. Словарь о различных библиотеках .NET. Дополнительную информацию см. в разделе Настройки проигрывателя и Оптимизация размера встроенного проигрывателя iOS. - Уменьшите размер содержимого. Используйте PVRTC сжатиеМетод хранения данных, который уменьшает требуемый объем дискового пространства. См. Сжатие текстур, Сжатие анимации, Сжатие звука, Сжатие компоновки.
См. в Словарь текстуры и использование низкополигональных моделей. Дополнительную информацию см. на странице руководства по уменьшению размера файла. - Не выделяйте в сценариях больше памяти, чем необходимо. Отслеживайте размер монофонической кучи и ее использование с помощью внутреннего профилировщика.
Запрос ОС об объеме свободной памяти может показаться хорошей идеей, чтобы оценить, насколько хорошо работает ваше приложение. Однако статистика свободной памяти, скорее всего, будет ненадежной, поскольку ОС использует много динамических буферов и кешей. Единственный надежный подход — отслеживать потребление памяти вашим приложением и использовать его в качестве основного показателя. Обратите внимание на то, как со временем меняются графики от описанных выше инструментов, особенно после загрузки новых уровней.
Игра работает корректно при запуске из Xcode, но вылетает при загрузке первого уровня при ручном запуске на устройстве.
Причин может быть несколько. Вам нужно проверить журналы устройства, чтобы получить более подробную информацию. Подключите устройство к вашему Mac, запустите Xcode и выберите в меню Окно > Устройства и симуляторы. Выберите свое устройство на левой панели инструментов окна, затем нажмите кнопку Показать консоль устройства и внимательно просмотрите последние сообщения. Кроме того, вам может потребоваться изучить отчеты о сбоях. Вы можете узнать, как получить отчеты о сбоях, здесь: http://developer.apple. com/iphone/library/technotes/tn2008/tn2151.
Консоль Xcode Organizer содержит сообщение «убито SpringBoard».
Существует плохо задокументированное ограничение времени для приложения iOS для рендеринга первых кадров и обработки ввода. Если ваше приложение превысит этот предел, оно будет уничтожено SpringBoard. Это может произойти в приложении с первой сценойСцена содержит окружение и меню вашей игры. Думайте о каждом уникальном файле сцены как об уникальном уровне. В каждой сцене вы размещаете свое окружение, препятствия и декорации, по сути проектируя и создавая свою игру по частям. Подробнее
См. в Словарь, например, слишком большой. Чтобы избежать этой проблемы, рекомендуется создать небольшую начальную сцену, которая просто отображает заставку, ждет один или два кадра с выходом, а затем начинает загрузку реальной сцены. Это можно сделать с помощью следующего простого кода:
IEnumerator Start() {
yield return new WaitForEndOfFrame();
// Do not forget using UnityEngine.SceneManagement directive
SceneManager.LoadScene("Test");
}
Type.GetProperty() или Type.GetValue() вызывают сбои на устройстве
В настоящее время Type.GetProperty() и Type.GetValue() поддерживаются только для профиля .NET 2.0 Subset. Вы можете выбрать уровень совместимости .NET API в настройках Player.
Примечание. Type.GetProperty() и Type.GetValue() могут быть несовместимы с управляемым удалением кода, и их может потребоваться исключить. (для этого вы можете предоставить пользовательский список типов, не подлежащих удалению, во время процесса удаления). Дополнительные сведения см. в руководстве по оптимизации размера проигрывателя iOS.
Игра вылетает с сообщением об ошибке «ExecutionEngineException: Попытка JIT-компиляции метода ‘SometType`1:.ctor ()’ при запуске с –aot-only».
Реализация Mono .NET для iOS основана на технологии AOT (упреждающая компиляция в машинный код), которая имеет свои ограничения. Он компилирует только те методы универсального типа (где тип значения используется в качестве универсального параметра), которые явно используются другим кодом. Когда такие методы используются только посредством отражения или из собственного кода (т. е. системы сериализации), они пропускаются во время компиляции AOTперед Компиляция Time (AOT) — это метод оптимизации iOS для оптимизации размера встроенного проигрывателя iOS. Подробнее
См. в Словарь. Компилятору AOT можно дать указание включить код, добавив фиктивный метод где-нибудь в код скрипта. Это может относиться к отсутствующим методам, поэтому их нужно скомпилировать заранее.
void _unusedMethod() {
var tmp = new SomeType();
}
Примечание. Типы значений — это базовые типы, перечисления и структуры.
При использовании комбинации System.Security.Cryptography и управляемого удаления кода на устройстве происходят различные сбои
Службы криптографии .NET в значительной степени зависят от отражения и поэтому несовместимы с управляемым удалением кода, поскольку оно требует статического анализа кода. Иногда самым простым решением сбоев является исключение всего пространства имен System.Security.Crypography из процесса очистки.
Процесс удаления можно настроить, добавив собственный файл link.xml в папку Assets вашего проекта Unity. Это указывает, какие типы и пространства имен следует исключить из удаления. Дополнительную информацию можно найти в руководстве по оптимизации размера проигрывателя iOS.
link.xml
Сбой приложения при использовании System.Security.Cryptography.MD5 с управляемым удалением кода
Вам следует принять во внимание приведенный выше совет или попытаться обойти эту проблему, добавив в код скрипта дополнительные ссылки на определенные классы:
object obj = new MD5CryptoServiceProvider();
Ошибка выполнения «Закончились батуты типа 0/1/2»
Эта ошибка обычно возникает, если вы используете много рекурсивных дженериков. Вы можете подсказать компилятору AOT выделить больше трамплинов типа 0, типа 1 или типа 2. Дополнительные параметры командной строки компилятора AOT можно указать в разделе Другие настройки класса Настройки игрока. Для батутов типа 0 укажите ntrampolines=ABCD
, где ABCD — количество необходимых новых батутов (например, 4096). Для батутов типа 1 укажите nrgctx-trampolines=ABCD
, а для батутов типа 2 укажите nimt-trampolines=ABCD
.
После обновления Xcode Unity iOS во время выполнения происходит сбой с сообщением «Вы используете Unity iPhone Basic. Вам не разрешено удалять заставку Unity из игры»
В некоторых последних выпусках Xcode были внесены изменения в инструмент сжатия и оптимизации PNG. Эти изменения могут привести к ложным срабатываниям при проверках среды выполнения Unity iOS на наличие модификаций экрана-заставки. Если вы столкнулись с такими проблемами, попробуйте обновить Unity до последней общедоступной версии. Если это не помогает, вы можете рассмотреть следующий обходной путь:
- Replace your Xcode project from scratch when building from Unity (instead of appending it)
- Delete already installed projects from device
- Clean project in Xcode (Product > Clean)
- Clear Xcode’s Derived Data folders (Xcode > Preferences > Locations)
If this still does not help try disabling PNG re-compression in Xcode:
- Откройте проект Xcode
- Выберите проект Unity-iPhone.
- Выберите вкладку Настройки сборки.
- Найдите параметр Сжимать файлы PNG и установите значение НЕТ.
WWW-загрузки работают нормально в редакторе Unity и на Android, но не на iOS
Самой распространенной ошибкой является предположение, что загрузка WWW всегда происходит в отдельном потоке. На некоторых платформах это может быть правдой, но вы не должны принимать это как должное. Лучший способ отслеживать статус WWW — использовать оператор yield или проверять статус в методе Update. Вы не должны не использовать для этого занятые циклы while.
«PlayerLoop вызывается рекурсивно!» ошибка возникает при использовании Cocoa через нативную функцию, вызываемую из скрипта
Некоторые операции с UI(пользовательский интерфейс) Позволяет пользователю взаимодействовать с вашим приложением. В настоящее время Unity поддерживает три системы пользовательского интерфейса. Подробнее
See in Словарь приведет к тому, что iOS немедленно перерисует окно (наиболее распространенный пример добавляет UIView с UIViewController в основной UIWindow). Если вы вызываете нативную функцию из скрипта, это происходит внутри PlayerLoop Unity, в результате чего PlayerLoop вызывается рекурсивно. В таких случаях следует рассмотреть возможность использования performSelectorOnMainThread с параметром waitUntilDone, установленным на false. Он сообщит iOS о необходимости запланировать выполнение операции между вызовами Unity PlayerLoop.
Профилировщик или отладчик не видит игру, работающую на устройстве iOS
- Убедитесь, что вы построили сборку для разработки, и установите флажки Отладка скриптов и Профилировщик автоподключения (если применимо).
- Приложение, работающее на устройстве, будет выполнять многоадресную рассылку на адрес 225.0.0.222 через UDP-порт 54997. Убедитесь, что настройки вашей сети разрешают этот трафик. Затем профилировщикокно, которое поможет вам оптимизировать игру. Он показывает, сколько времени вы тратите на различные области вашей игры. Например, он может сообщать о проценте времени, затраченном на рендеринг, анимацию или игровую логику. Дополнительная информация
См. в Словарь установит соединение с удаленным устройством через порт в диапазон 55000 - 55511 для получения данных профилировщика с устройства. Эти порты должны быть открыты для доступа TCP.
Отсутствуют библиотеки DLL
Если ваше приложение работает нормально в редакторе, но вы получаете ошибки в своем проекте iOS, это может быть вызвано отсутствием библиотек DLL (например, I18N.dll, I19N.West.dll). В этом случае попробуйте скопировать эти DLL из Unity.app в папку Assets\Plugins вашего проекта. Расположение DLL в приложении Unity: Unity.app\Contents\Frameworks\Mono\lib\mono\unity Затем вы также должны проверить уровень удаления вашего проекта, чтобы убедиться, что классы в библиотеках DLL не удаляются при оптимизации сборки. Дополнительную информацию об уровнях разделения iOS см. на странице оптимизации iOS.
Отчеты консоли отладчика Xcode: ExecutionEngineException: попытка метода JIT-компиляции ‘(оболочка, встроенная в управляемую) Test:TestFunc (int)’ при работе с –aot-only
Обычно такое сообщение появляется, когда делегат управляемой функции передается в собственную функцию, но требуемый код оболочки не был сгенерирован при сборке приложения. Вы можете помочь компилятору AOT, подсказав, какие методы будут переданы в качестве делегатов нативному коду. Это можно сделать, добавив настраиваемый атрибут MonoPInvokeCallbackAttribute. В настоящее время только статические методы можно передавать в качестве делегатов нативному коду.
Пример кода:
using UnityEngine;
using System.Collections;
using System;
using System.Runtime.InteropServices;
using AOT;
public class NewBehaviourScript : MonoBehaviour {
[DllImport ("__Internal")]
private static extern void DoSomething (NoParamDelegate del1, StringParamDelegate del2);
delegate void NoParamDelegate ();
delegate void StringParamDelegate (string str);
[MonoPInvokeCallback(typeof(NoParamDelegate))]
public static void NoParamCallback() {
Debug.Log ("Hello from NoParamCallback");
}
[MonoPInvokeCallback(typeof(StringParamDelegate))]
public static void StringParamCallback(string str) {
Debug.Log(string.Format("Hello from StringParamCallback {0}", str));
}
// Use this for initialization
void Start() {
DoSomething(NoParamCallback, StringParamCallback);
}
}
Xcode выдает ошибку компиляции: «ld: невозможно вставить остров ответвления. Точка вставки отсутствует. для архитектуры armv7», «clang: ошибка: команда компоновщика завершилась с кодом выхода 1 (используйте -v, чтобы увидеть вызов)»
Эта ошибка обычно означает, что в одном модуле слишком много кода. Как правило, это вызвано наличием большого количества кода скрипта или включением в сборку больших внешних сборок .NET. А включение отладки скриптов может еще больше усугубить ситуацию, потому что к каждой функции добавляется довольно мало дополнительных инструкций, поэтому этот предел легче достичь.
Включение управляемого удаления кода в настройках Player может решить эту проблему, особенно если задействованы большие внешние сборки .NET. Но если проблема не устранена, лучшим решением будет разбить код пользовательского скрипта на несколько сборок. Самый простой способ это переместить код в папку Plugins. Код в этом месте помещается в другую сборку. Кроме того, проверьте информацию о том, как названия специальных папок влияют на компиляцию скрипта.