Características actualmente no soportadas por Unity iOS.
Reportando bugs de falla en iOS

Troubleshooting en dispositivos iOS

Hay algunas situaciones con iOS donde su juego puede funcionar perfectamente en el Editor de Unity pero no funciona o, ni siquiera comienza en el dispositivo actual. Los problemas a menudos están relacionados al código o la calidad de contenido. Esta sección describe los escenarios más comunes.

El juego para de responder después de un poco. Xcode muestra “interrupted” en la barra de estado.

Hay un número de razones de por qué esto puede suceder. Las causas típicas incluyen:

  1. Errores de Scripting como el uso de variables no inicializadas, etc.
  2. Utilizar librerías de nativas compiladas de terceros. Tales librerías activa un problema conocido en el linker del SDK de iOS y puede causar problemas(crashes) aleatorios.
  3. Utilizar tipos génericos con tipos de valores como parámetros (eg List<int>, List<SomeStruct>, List<SomeEnum>, etc) para propiedades de script serializables.
  4. Utilizar reflexión cuando managed code stripping esté activado.
  5. Errores en la intefaz de plugin nativa (el método para manejar código signature no concuerda con la función de código nativo signature). La información de la consola de depuración Xcode puede a veces ayudar a detectar estos problemas (Menú de Xcode: View > Debug Area > Activate Console).

La consola de Xcode muestra "Program received signal: “SIGBUS” o EXC_BAD_ACCESS error.

Este mensaje típicamente aparece en dispositivos iOS cuando su aplicación recibe una NullReferenceException. Hay dos maneras para descifrar dónde ocurrió la falta:

Administrar los seguimientos de pila (Managed Stack Traces)

Unity incluye software base del manejo de NullReferenceException. El compilador AOT incluye unas revisiones rápidas para referencias nulas cada vez que un método o variable se accede en un objeto. Esta característica afecta el rendimiento script por lo que sólo se habilita para las compilaciones de desarrollo (habilite la opción “depuración de script” en el cuadro de diálogo de configuración de compilación). Si todo fue hecho de manera correcta, y la falla está ocurriendo en el código .NET entonces usted no verá EXC_BAD_ACCESS más. Más bien, el texto de la excepción .NET será imprimida en la consola de Xcode (o su código solo lo manejará en una declaración “catch”). El output típico puede ser:

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 

Esto indica que la falla ocurrió en el método handleTimeOfDay de la clase DayController, que funciona como una coroutine. También si es código script entonces a usted se le dirá por lo genera el número de la linea exacta (eg, “DayController.js:122”). La linea que causa los problemas puede ser como la siguiente:

 Instantiate(_imgwww.assetBundle.mainAsset);

Esto puede suceder si, digamos, el script accede un asset bundle sin primero revisar que fuera descargado correctamente.

Seguimientos de pila nativos (Native stack traces)

Los rastros de pila nativos son una herramienta más poderosa para la investigación de fallas pero utilizarlas requiere algo de experiencia. También, por lo general usted no puede continuar después de que suceda estas fallas (acceso de memoria en el hardware) nativas sucedan. Para obtener un rastro de pila nativo, ingrese bt all a la consola de depuración Xcode. Cuidadosamente inspeccione los rastros de pila impresos - pueden contener sugerencias acerca dónde el error ocurrió. Podría ver algo como:

...
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 ()
...

Primero que todo, usted debería encontrar el rastro de pila para “Thread 1”, el cual es el hilo principal. Las primeras lineas del rastro de pila van a apuntar al lugar dónde el error ocurrió. En este ejemplo, el rastro indico que la NullReferenceException sucedió en “OptionsMenu” dentro del método “Start” del script. Mirando de manera cuidadosa la implementación de este método va a mostrar la causa del problema. Típicamente, la NullReferenceExceptions sucede dentro del método Start cuando se hacen suposiciones incorrectas sobre el orden de inicialización.de inicialización. En algunos casos solo un seguimiento de pila parcial es visto en la Consola Debugger:

Thread 1 (thread 11523): 

1. 0 0x0062564c in start ()

Esto indica que los símbolos nativos fueron stripped durante la construcción final de la aplicación. El seguimiento de pila completo puede ser obtenido con los siguiente procedimientos:

  • Quite la aplicación del dispositivo.
  • Limpie todos los objetivos (targets)
  • Construya y corra.
  • Obtenga los seguimiento de pila nuevamente como es descrito arriba.

EXC_BAD_ACCESS comienza ocurriendo cuando una librería externa está vinculada a la aplicación de Unity iOS.

Esto por lo general ocurre cuando una librería externa es compilada con el conjunto de instrucciones Thumb de ARM. Actualmente tales librerías no son compatibles con Unity. El problema puede ser resuelto fácilmente re-compilando la librería sin las instrucciones Thumb. Usted puede hacer esto para el proyecto Xcode de la librería con los siguientes pasos:

  • en Xcode, seleccione “View” > “Navigators” > “Show Project Navigator” desde el menú.
  • Seleccione el proyecto “Unity-iPhone”, active la pestaña “Build Settings”
  • en el campo de búsqueda escriba: “Other C Flags”
  • Agregue -mno-thumb flag ahí y re-construya la librería.

Si la fuente de la librería no está disponible, usted debería preguntarle al proveedor por una versión sin-thumb de la librería.

La consola de Xcode muestra “WARNING -> applicationDidReceiveMemoryWarning()” y la aplicación cae inmediatamente después

(algunas veces usted podría ver un mensaje como Program received signal: “0”.) Este mensaje de advertencia a menudo no es fatal y a penas indica que el iOS está bajo en memoria y está preguntando por aplicaciones para liberar alguna memoria. Típicamente, los procesos del fondo como el Correo van a liberar alguna memoria y su aplicación puede continuar corriendo. Sin embargo, si su aplicación continua utilizando memoria o pregunta para más, el OS va a eventualmente comenzar a destruir aplicaciones y la suya puede ser una de ellas. Apple no documenta qué uso de memoria es segura, pero observaciones empíricas muestra que aplicaciones utilizando mensos que el 50% MB de toda la RAM del dispositivo (aproximadamente 200–256 MB para la segunda generación de ipad) no tienen problema mayores de uso de memoria. La métrica principal en la que debe confiar es la cantidad de RAM que utiliza su aplicación. El uso de la memoria de aplicaciones consta de tres componentes principales:

  • código de aplicación (el sistema operativo necesita cargar y mantener su código de aplicación en RAM, pero algunos de ellos pueden ser desechados si es necesario)
  • heap nativo (utilizado por el motor para almacenar su estado, sus assets, etc en RAM)
  • heap gestionado (utilizado por su tiempo de ejecución Mono para mantener objetos C# o JavaScript)
  • Las piscinas de memoria de controladores GLES: texturas, framebuffers, shaders compilados, etc. El uso de memoria de aplicación se puede rastrear por dos herramientas de Xcode: Activity Monitor, Object Allocations y VM Tracker. Puede comenzar desde el menú Xcode Run: Product > Profile y luego seleccione la herramienta específica. La herramienta Activity Monitor muestra todas las estadísticas del proceso, incluyendo Real memory, que puede considerarse como la cantidad total de RAM utilizada por su aplicación. Nota: La combinación de versión OS y dispositivo HW podría afectar notablemente los números del uso de memoria, por lo que debe tener cuidado al comparar los números obtenidos en diferentes dispositivos.

** Nota:** El internal profiler muestra sólo el heap asignado por los scripts de .NET. El uso total de memoria se puede determinar a través de las herramientas de Xcode como se muestra arriba. Esta figura incluye partes del binario de la aplicación, algunos búferes de marco estándar, búferes de estado interno del motor Unity, el heap de ejecución .NET (número impreso por el internal profiler), el heap de controladores GLES y algunas otras cosas misceláneas.

La otra herramienta muestra todas las asignaciones realizadas por su aplicación e incluye estadísticas de heap nativas y heap gestionadas (no olvide marcar la caja Created y still living para obtener el estado actual de la aplicación). La estadística importante es el valor Net bytes.

Para mantener el uso de memoria bajo:

  • Reduzca el tamaño binario de la aplicación utilizando las opciones de stripping de iOS más fuertes y evite dependencias innecesarias en diferentes bibliotecas .NET. Consulte las páginas de manual de player settings y player size optimization para obtener más detalles.
  • Reduzca el tamaño de su contenido. Utilice la compresión de PVRTC para texturas y utilice modelos de bajo peso. Consulte la página del manual acerca de reducir el tamaño del archivo para obtener más información.
  • No asigne más memoria de la necesaria en sus scripts. Monitorear el tamaño y el uso del heap mono con el internal profiler
  • Nota: con Unity 3.0, la implementación de carga de escenas ha cambiado significativamente y ahora todos los assets de la escena están precargados. Esto resulta en menos problemas al instanciar game objects. Si necesita un control más detallado de la carga y descarga de assets durante el juego, debe utilizar Resources.Load y Object.Destroy.

Consultar el sistema operativo acerca de la cantidad de memoria libre puede parecer una buena idea para evaluar qué tan bien está ejecutándose su aplicación. Sin embargo, la estadística de memoria libre es probable que no sea fiable ya que el sistema operativo utiliza una gran cantidad de búferes dinámicos y cachés. El único enfoque fiable es realizar un seguimiento del consumo de memoria para su aplicación y utilizarlo como la métrica principal. Preste atención a cómo las gráficas de las herramientas descritas anteriormente cambian con el tiempo, especialmente después de cargar nuevos niveles.

El juego se ejecuta correctamente cuando se inicia desde Xcode pero se bloquea al cargar el primer nivel cuando se inicia manualmente en el dispositivo.

Podría haber varias razones para esto. Debe inspeccionar los registros del dispositivo para obtener más detalles. Conecte el dispositivo a su Mac, ejecute Xcode y seleccione Window > Organizer en el menú. Seleccione su dispositivo en la barra de herramientas izquierda del Organizador, luego haga clic en la pestaña “Console” y revise cuidadosamente los últimos mensajes. Además, es posible que necesite investigar los informes de fallos. Puede averiguar cómo obtener informes de fallo aquí: http://developer.apple.com/iphone/library/technotes/tn2008/tn2151.html.

La consola del organizador de Xcode contiene el mensaje “killed by SpringBoard”.

Hay un límite de tiempo mal documentado para una aplicación de iOS para renderizar sus primeros frames y procesar input. Si su aplicación excede este límite, SpringBoard lo matará. Esto puede ocurrir en una aplicación con una primera escena demasiado grande, por ejemplo. Para evitar este problema, es aconsejable crear una pequeña escena inicial que sólo muestra una pantalla de bienvenida, espera un frame o dos con yield y luego comenzar a cargar la escena real. Esto se puede hacer con un código tan sencillo como el siguiente:

function Start() {
    yield;
    Application.LoadLevel("Test");
}

Type.GetProperty() / Type.GetValue() causa fallos en el dispositivo

Actualmente Type.GetProperty() y Type.GetValue() están soportados sólo para el perfil .NET 2.0 Subset. Puede seleccionar el nivel de compatibilidad de .NET API en el Player Settings.

Nota: Type.GetProperty() y Type.GetValue() podrían ser incompatibles con la eliminación de código administrado y puede que tenga que ser excluido (puede proporcionar una lista de tipos no desplegables personalizada durante el proceso de eliminación para lograr esto). Para obtener más detalles, consulte la guía iOS player size optimization.

El juego falla con el mensaje de error “ExecutionEngineException: Attempting to JIT compile method ‘SometType`1<SomeValueType>:.ctor ()’ while running with –aot-only.”

La implementación de Mono .NET para iOS se basa en la tecnología AOT (antes de la compilación de código nativo), que tiene sus limitaciones. Compila sólo aquellos métodos de tipo genérico (donde un tipo de valor se utiliza como un parámetro genérico) que se utilizan explícitamente por otro código. Cuando tales métodos se utilizan sólo a través de la reflexión o desde código nativo (es decir, el sistema de serialización), entonces se saltan durante la compilación AOT. El compilador AOT se puede sugerir para incluir código añadiendo un método ficticio en algún lugar del código script. Esto puede referirse a los métodos que faltan y así obtenerlos compilados antes de tiempo.

void _unusedMethod() {
    var tmp = new SomeType<SomeValueType>();
}

Nota: los tipos de valor son tipos básicos, enums y structs.

Se producen varias fallas en el dispositivo cuando se usa una combinación de System.Security.Cryptography y stripping de código administrado

Los servicios de .NET Cryptography dependen en gran medida de la reflexión y, por lo tanto, no son compatibles con el descifrado de código administrado, ya que esto implica el análisis de código estático. A veces, la solución más fácil para los bloqueos es excluir todo el namespace System.Security.Crypography del proceso de stripping.

El proceso de stripping se puede personalizar añadiendo un archivo personalizado link.xml a la carpeta Assets de su proyecto Unity. Esto especifica qué tipos y namespaces se deben excluir de stripping. Más detalles se pueden encontrar en la guía iOS player size optimization.

link.xml

<linker>
       <assembly fullname="mscorlib">
               <namespace fullname="System.Security.Cryptography" preserve="all"/>
       </assembly>
</linker>

La aplicación falla cuando se utiliza System.Security.Cryptography.MD5 con stripping de código manejado

Es posible que considere consejos enumerados anteriormente o puede solucionar este problema agregando referencia adicional a una clase específica a su código de script:

object obj = new MD5CryptoServiceProvider();

“Ran out of trampolines of type 0/1/2” runtime error

Este error suele suceder si utiliza un montón de genéricos recursivos. Puede sugerir al compilador AOT que asigne más trampolines de tipo 0, tipo 1 o tipo 2. Las opciones adicionales de la línea de comandos del compilador AOT se pueden especificar en la sección “Other Settings” de la sección de Player Settings. Para los trampolines tipo 1, especifique nrgctx-trampolines=ABCD, donde ABCD es el número de trampolines nuevos requeridos (es decir, 4096). Para trampolines tipo 2, especifique nimt-trampolines=ABCD y para trampolines tipo 0 especifique ntrampolines=ABCD.

Después de actualizar Xcode Unity el tiempo de ejecución de iOS falla con el mensaje “You are using Unity iPhone Basic. You are not allowed to remove the Unity splash screen from your game”

Con algunas últimas versiones de Xcode se introdujeron cambios en la compresión de PNG y la herramienta de optimización. Estos cambios pueden causar falsos positivos en las comprobaciones de tiempo de ejecución de Unity iOS para las modificaciones del splash screen. Si experimenta estos problemas, intente actualizar Unity a la última versión disponible públicamente. Si no le ayuda, puedes considerar la siguiente solución:

  • Reemplace su proyecto de Xcode desde cero cuando construya desde Unity (en lugar de anexarlo)

  • Borre el proyecto ya instalado del dispositivo

  • Clean el proyecto en Xcode (Product->Clean)

  • Limpie las carpetas de Datos Derivados de Xcode (Xcode->Preferences->Locations) Si esto todavía no ayuda intente inhabilitar la re-compresión del png en Xcode:

  • Abra su proyecto de Xcode

  • Seleccione el proyecto “Unity-iPhone” ahí

  • Seleccione la pestaña “Build Settings” ahí

  • Busque por la opción “Compress PNG files” y configure esto a NO

La presentación de la App Store falla con el mensaje “iPhone/iPod Touch: application executable is missing a required architecture. At least one of the following architecture(s) must be present: armv6”

Es posible que reciba este mensaje al actualizar una aplicación ya existente, que previamente fue enviada con el soporte de armv6. Unity 4.x y Xcode 4.5 no soportan más la plataforma armv6. Para solucionar el problema del envió simplemente configure Target OS Version en las Player Settings de Unity a 4.3 o superior.

Las descargas de WWW funcionan bien en el Unity Editor y en Android, pero no en iOS

El error más común es asumir que las descargas de WWW siempre están ocurriendo en hilos separados. En algunas plataformas esto puede ser cierto, pero no debe darse por sentado. La mejor manera de rastrear el estado de WWW es usar la instrucción yield o comprobar el estado en el método Update. Usted no debe utilizar bucles ocupados while para eso.

El error “PlayerLoop called recursively!” ocurre cuando se utiliza Cocoa mediante un llamado de función nativo desde un script

Algunas operaciones con la interfaz de usuario harán que iOS vuelva a dibujar la ventana inmediatamente (el ejemplo más común es agregar una UIView con un UIViewController a la UIWindow principal). Si llama a una función nativa de un script, sucederá dentro del PlayerLoop de Unity, resultando en que PlayerLoop se llame recursivamente. En estos casos, debe considerar el uso de la herramienta performSelectorOnMainThread método con waitUntilDone establecido en false. Informará a iOS para programar la operación que se ejecutará entre las llamadas PlayerLoop de Unity.

El Profiler o Depurador incapaz de ver el juego corriendo en el dispositivo iOS

  • Revise que tenga una construcción Development build, y tiene marcado las casillas “Enable Script Debugging” y “Autoconnect profiler” (como sea adecuado).
  • La aplicación que se ejecuta en el dispositivo hará una difusión multicast a 225.0.0.222 en el puerto UDP 54997. Compruebe que la configuración de red permite este tráfico. A continuación, el profiler realizará una conexión al dispositivo remoto en un puerto del rango 55000 - 55511 para obtener datos del profiler del dispositivo. Estos puertos necesitarán estar abiertos para el acceso UDP.

DLLs faltantes

Si su aplicación corre bien en el editor pero tiene errores en su proyecto iOS esto podría ser causado por DLLs que faltan(e.g. I18N.dll, I19N.West.dll). En este caso, intente copiar estas dlls desde dentro del Unity.app a la carpeta Assets/Plugins de su proyecto. La ubicación de los DLLs dentro de la unity app es: Unity.app/Contents/Frameworks/Mono/lib/mono/unity También debe comprobar el nivel de stripping de su proyecto para asegurarse de que las clases de las DLL no se eliminan cuando se optimiza la generación. Consulte la [Página de optimización de iOS](iphone-playerSizeOptimization para obtener más información sobre los niveles de stripping de iOS.

Informes de la consola del depurador de Xcode: ExecutionEngineException: intentar el método de compilación JIT ‘(wrapper nativo a administrado) Test: TestFunc (int)’ mientras se ejecuta con –aot-only

Normalmente, este tipo de mensaje se recibe cuando un delegado de función administrada se pasa a la función nativa, pero no se generó el código de contenedor necesario al crear la aplicación. Puede ayudar al compilador de AOT indicando qué métodos se pasarán como delegados al código nativo. Esto puede hacerse agregando el atributo personalizado “MonoPInvokeCallbackAttribute”. Actualmente sólo los métodos estáticos se pueden pasar como delegados al código nativo.

Código ejemplo:

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 lanza error de compilación: “ld : unable to insert branch island. No insertion point available. for architecture armv7”, “clang: error: linker command failed with exit code 1 (use -v to see invocation)”

Ese error generalmente significa que hay demasiado código en un solo módulo. Normalmente es causado por tener un montón de código de script o tener grandes ensamblados externos. NET incluidos en la construcción. Y la habilitación de la depuración de scripting podría empeorar las cosas, ya que añade muy pocas instrucciones adicionales a cada función, por lo que es más fácil superar ese límite.

Habilitar el stripping de código administrado en los player settings podrían ayudar con este problema, especialmente si están involucrados grandes ensamblados .NET externos. Pero si el problema persiste, entonces la mejor solución es dividir el código de script del usuario en varios ensamblajes. La forma más fácil de esto es mover algún código a la carpeta Plugins. El código en esta ubicación se coloca en un ensamblaje diferente. También comprueba la información acerca de cómo los nombres especiales de carpetas afectan la compilación de scripting:

Características actualmente no soportadas por Unity iOS.
Reportando bugs de falla en iOS