Comprende las fallas de un juego de Unity con las funciones avanzadas de Crashlytics

1. Introducción

En este codelab, aprenderás a usar las funciones avanzadas de Crashlytics, que te darán una mejor visibilidad de las fallas y las circunstancias que podrían haberlas causado.

Agregarás funcionalidad nueva a un juego de muestra, MechaHamster: Sube de nivel con Firebase Edition. Este juego de muestra es una versión nueva del clásico juego de Firebase MechaHamster que quita la mayoría de sus funciones integradas de Firebase, lo que te da la oportunidad de implementar nuevos usos de Firebase en su lugar.

Agregarás un menú de depuración al juego. Este menú de depuración llama a los métodos que crearás y te permite usar las diferentes funciones de Crashlytics. Estos métodos te mostrarán cómo anotar tus informes de fallas automáticos con claves personalizadas, registros personalizados, errores recuperables y mucho más.

Después de compilar el juego, usarás el menú de depuración y, luego, inspeccionarás los resultados para comprender la vista única que proporcionan sobre cómo se ejecuta tu juego de forma salvaje.

Qué aprenderás

  • Los tipos de errores que Crashlytics detecta automáticamente.
  • Errores adicionales que se pueden registrar deliberadamente.
  • Cómo agregar más información a estos errores para que sean más fáciles de entender

Requisitos

  • Unity (versión mínima recomendada de 2019 y versiones posteriores) con una de las siguientes opciones o ambas:
    • Compatibilidad con la compilación de iOS
    • Compatibilidad con la compilación de Android
  • (Solo para Android) Firebase CLI (se usa para subir símbolos para informes de fallas)

2. Configura tu entorno de desarrollo

En las siguientes secciones, se describe cómo descargar el código para subir de nivel con Firebase y abrirlo en Unity.

Ten en cuenta que este juego de muestra para subir de nivel con Firebase se usa en muchos otros codelabs de Firebase y Unity, por lo que es posible que ya hayas completado las tareas de esta sección. Si es así, puedes ir directamente al último paso de esta página: “Agrega los SDK de Firebase para Unity”.

Descarga el código

Clona el repositorio de GitHub de este codelab desde la línea de comandos:

git clone https://github.com/firebase/level-up-with-firebase.git

Como alternativa, si no tienes Git instalado, puedes descargar el repositorio como archivo ZIP.

Abre Sube de nivel con Firebase en el editor de Unity

  1. Inicia Unity Hub y, en la pestaña Projects, haz clic en la flecha desplegable junto a Open.
  2. Haz clic en Agregar proyecto desde el disco.
  3. Navega al directorio que contiene el código y, luego, haz clic en OK.
  4. Si se te solicita, selecciona una versión del editor de Unity y tu plataforma de segmentación (Android o iOS).
  5. Haz clic en el nombre del proyecto, level-up-with-firebase, y el proyecto se abrirá en el editor de Unity.
  6. Si el editor no lo abre automáticamente, abre MainGameScene en Assets > Hamster en la pestaña Project de Unity Editor.
    ff4ea3f3c0d29379.png

Para obtener más información sobre la instalación y el uso de Unity, consulta Cómo trabajar en Unity.

3. Agrega Firebase a tu proyecto de Unity

Crea un proyecto de Firebase

  1. En Firebase console, haz clic en Agregar proyecto.
  2. Para crear un proyecto nuevo, ingresa el nombre que quieras.
    Con esto, también se configurará el ID del proyecto (que se muestra debajo del nombre del proyecto) según ese nombre. De manera opcional, puedes hacer clic en el ícono de edición en el ID del proyecto para personalizarlo aún más.
  3. Si se te solicita, revisa y acepta las Condiciones de Firebase.
  4. Haz clic en Continuar.
  5. Selecciona la opción Habilitar Google Analytics para este proyecto y, luego, haz clic en Continuar.
  6. Selecciona una cuenta de Google Analytics existente para usar o elige Crear una cuenta nueva para crear una nueva.
  7. Haz clic en Crear proyecto.
  8. Cuando se haya creado el proyecto, haz clic en Continuar.

Registra tu app en Firebase

  1. En Firebase console, en el centro de la página de descripción general del proyecto, haz clic en el ícono de Unity para iniciar el flujo de trabajo de configuración o, si ya agregaste una app a tu proyecto de Firebase, haz clic en Agregar app para que se muestren las opciones de la plataforma.
  2. Selecciona esta opción para registrar los destinos de compilación de Apple (iOS) y Android.
  3. Ingresa los IDs específicos de la plataforma del proyecto de Unity. En este codelab, ingresa lo siguiente:
  4. Ingresa el sobrenombre específico de cada plataforma para tu proyecto de Unity (opcional).
  5. Haz clic en Registrar app y, luego, ve a la sección Descargar archivo de configuración.

Agrega los archivos de configuración de Firebase

Después de hacer clic en Registrar app, se te pedirá que descargues dos archivos de configuración (uno para cada destino de compilación). Tu proyecto de Unity necesita los metadatos de Firebase en estos archivos para conectarse con Firebase.

  1. Descarga los dos archivos de configuración disponibles:
    • En Apple (iOS): Descarga GoogleService-Info.plist.
    • Para Android: Descarga google-services.json.
  2. Abre la ventana Project de tu proyecto de Unity y transfiere ambos archivos de configuración a la carpeta Assets.
  3. Vuelve a Firebase console, en el flujo de trabajo de configuración, haz clic en Siguiente y continúa con la sección Agregar los SDK de Firebase para Unity.

Agrega los SDK de Firebase para Unity

  1. Haz clic en Descargar el SDK de Firebase Unity en Firebase console.
  2. Descomprime el SDK en el lugar que prefieras.
  3. Abre el proyecto de Unity, ve a Assets > Import Package > Custom Package.
  4. En el diálogo Import package, navega al directorio que contiene el SDK descomprimido, selecciona FirebaseAnalytics.unitypackage y, luego, haz clic en Abrir.
  5. En el diálogo Import Unity Package que aparece, haz clic en Import.
  6. Repite los pasos anteriores para importar FirebaseCrashlytics.unitypackage.
  7. Vuelve a Firebase console y, en el flujo de trabajo de configuración, haz clic en Siguiente.

Si quieres obtener más información para agregar los SDK de Firebase a proyectos de Unity, consulta Opciones adicionales de instalación de Unity.

4. Configura Crashlytics en tu proyecto de Unity

Para usar Crashlytics en proyectos de Unity, deberás seguir algunos pasos de configuración más. Por supuesto, deberás inicializar el SDK. Sin embargo, también deberás subir tus símbolos para ver los seguimientos de pila simbolizados en Firebase console y forzar una falla de prueba para asegurarte de que Firebase reciba tus eventos de falla.

Inicializa el SDK de Crashlytics

  1. En Assets/Hamster/Scripts/MainGame.cs, agrega las siguientes sentencias using:
    using Firebase.Crashlytics;
    using Firebase.Extensions;
    
    El primer módulo te permite usar métodos del SDK de Crashlytics y el segundo contiene algunas extensiones de la API de C# Tasks. Sin ambas sentencias, using, el siguiente código no funcionará.
  2. Aún en MainGame.cs, agrega la inicialización de Firebase al método Start() existente llamando a InitializeFirebaseAndStartGame():
    void Start()
    {
      Screen.SetResolution(Screen.width / 2, Screen.height / 2, true);
      InitializeFirebaseAndStartGame();
    }
    
  3. Una vez más, en MainGame.cs, busca InitializeFirebaseAndStartGame(), declara una variable de app y reemplaza la implementación del método de la siguiente manera:
    public Firebase.FirebaseApp app = null;
    
    // Begins the firebase initialization process and afterwards, opens the main menu.
    private void InitializeFirebaseAndStartGame()
    {
      Firebase.FirebaseApp.CheckAndFixDependenciesAsync()
      .ContinueWithOnMainThread(
        previousTask => 
        {
          var dependencyStatus = previousTask.Result;
          if (dependencyStatus == Firebase.DependencyStatus.Available) {
            // Create and hold a reference to your FirebaseApp,
            app = Firebase.FirebaseApp.DefaultInstance;
            // Set the recommended Crashlytics uncaught exception behavior.
            Crashlytics.ReportUncaughtExceptionsAsFatal = true;
            InitializeCommonDataAndStartGame();
          } else {
            UnityEngine.Debug.LogError(
              $"Could not resolve all Firebase dependencies: {dependencyStatus}\n" +
              "Firebase Unity SDK is not safe to use here");
          }
        });
    }
    

Colocar la lógica de inicialización aquí evita la interacción del jugador antes de que se inicialicen las dependencias de Firebase.

Los beneficios y efectos de informar excepciones no controladas como recuperables se analizan en las Preguntas frecuentes de Crashlytics.

Crea tu proyecto y sube símbolos

Los pasos para crear y subir símbolos son diferentes según se trate de apps para iOS o Android.

iOS+ (plataforma de Apple)

  1. Desde el diálogo Build Settings, exporta tu proyecto a un lugar de trabajo de Xcode.
  2. Compila tu app.
    En las plataformas de Apple, el complemento de Firebase Unity Editor configura automáticamente tu proyecto de Xcode para generar y subir un archivo de símbolos compatible con Crashlytics para los servidores de Firebase de cada compilación. Esta información de símbolos es necesaria para ver seguimientos de pila simbolizados en el panel de Crashlytics.

Android

  1. (solo durante la configuración inicial, no para cada compilación) Configura tu compilación:
    1. Crea una carpeta nueva llamada Builds en la raíz del directorio de tu proyecto (es decir, como elemento del mismo nivel que el directorio Assets) y, luego, crea una subcarpeta llamada Android.
    2. En File > Build Settings > Player Settings > Configuration, establece Scripting Backend en IL2CPP.
      • Por lo general, IL2CPP hace que las compilaciones sean más pequeñas y tengan un mejor rendimiento.
      • IL2CPP también es la ÚNICA opción disponible en iOS y seleccionarla aquí permite que las dos plataformas estén en una mejor paridad y simplificar las diferencias de depuración entre ambas (si eliges crear ambas).
  2. Compila tu app. En File > Build Settings, completa lo siguiente:
    1. Asegúrate de que la opción Crear símbolos.zip esté marcada (o, si aparece un menú desplegable, selecciona Depuración).
    2. Compila tu APK directamente desde Unity Editor en la subcarpeta Builds/Android que acabas de crear.
  3. Una vez que se complete la compilación, deberás generar un archivo de símbolos compatible con Crashlytics y subirlo a los servidores de Firebase. Esta información de símbolos es necesaria para ver los seguimientos de pila simbolizados de las fallas de bibliotecas nativas en el panel de Crashlytics.

    Genera y sube este archivo de símbolos ejecutando el siguiente comando de Firebase CLI:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    • FIREBASE_APP_ID: Es el ID de la app de Firebase para Android (no el nombre del paquete). Busca este valor en el archivo google-services.json que descargaste antes. Es el valor mobilesdk_app_id.
      ID de ejemplo de la app de Firebase para Android: 1:567383003300:android:17104a2ced0c9b9b
    • PATH/TO/SYMBOLS: Es la ruta de acceso del archivo de símbolos comprimidos generado en el directorio Builds/Android cuando finalizó la compilación (por ejemplo: Builds/Android/myapp-1.0-v100.symbols.zip).

Fuerza una falla de prueba para finalizar la configuración

Para terminar de configurar Crashlytics y ver los datos iniciales en el panel de Crashlytics de Firebase console, debes forzar una falla de prueba.

  1. En MainGameScene, busca EmptyObjectGameObject en el editor de Hierarchy, agrégale la siguiente secuencia de comandos y, luego, guarda la escena. Esta secuencia de comandos provocará una falla de prueba unos segundos después de que ejecutes la app.
    using System;
    using UnityEngine;
    
    public class CrashlyticsTester : MonoBehaviour {
        // Update is called once per frame
        void Update()
        {
            // Tests your Crashlytics implementation by
            // throwing an exception every 60 frames.
            // You should see reports in the Firebase console
            // a few minutes after running your app with this method.
            if(Time.frameCount >0 && (Time.frameCount%60) == 0)
            {
                throw new System.Exception("Test exception; please ignore");
            }
        }
    }
    
  2. Compila tu app y sube la información de los símbolos cuando finalice el proceso.
    • iOS: El complemento de Firebase Unity Editor configura automáticamente tu proyecto de Xcode para subir el archivo de símbolos.
    • Android: Ejecuta el comando crashlytics:symbols:upload de Firebase CLI para subir tu archivo de símbolos.
  3. Ejecuta la app. Una vez que se ejecute, mira el registro del dispositivo y espera a que se active la excepción desde CrashlyticsTester.
    • iOS: Puedes ver los registros en el panel inferior de Xcode.
    • Android: Ejecuta el siguiente comando en la terminal para ver los registros: adb logcat.
  4. Visita el panel de Crashlytics para ver la excepción. Lo verás en la tabla Problemas en la parte inferior del panel. Más adelante en el codelab, aprenderás a explorar estos informes.
  5. Una vez que confirmes que el evento se subió a Crashlytics, selecciona el EmptyObject GameObject al que lo adjuntaste, quita solo el componente CrashlyticsTester y guarda la escena para restablecerlo a su condición original.

5. Cómo habilitar y comprender el menú de depuración

Hasta ahora, agregaste Crashlytics a tu proyecto de Unity, terminaste la configuración y confirmaste que el SDK de Crashlytics sube eventos a Firebase. Ahora, crearás un menú en tu proyecto de Unity que demostrará cómo usar la funcionalidad de Crashlytics más avanzada en tu juego. El proyecto de Unity para subir de nivel con Firebase ya tiene un menú de depuración oculto que podrás ver y para el que escribirás la funcionalidad.

Cómo habilitar el menú de depuración

El botón para acceder al menú de depuración existe en tu proyecto de Unity, pero no está habilitado en este momento. Debes habilitar el botón para acceder a él desde el prefab MainMenu:

  1. En Unity Editor, abre el prefab llamado MainMenu.4148538cbe9f36c5.png
  2. En la jerarquía de prefab, busca el subobjeto inhabilitado llamado DebugMenuButton y, luego, selecciónalo.816f8f9366280f6c.png
  3. Para habilitar DebugMenuButton, marca la casilla en la esquina superior izquierda, a la izquierda del campo de texto que contiene DebugMenuButton.8a8089d2b4886da2.png
  4. Guarda el prefab.
  5. Ejecuta el juego en el editor o en tu dispositivo. Ahora se debería poder acceder al menú.

Obtén una vista previa y comprende los cuerpos de los métodos para el menú de depuración

Más adelante en este codelab, escribirás cuerpos de métodos para algunos métodos de depuración de Crashlytics preconfigurados. Sin embargo, en el proyecto de Unity de Level Up with Firebase, los métodos se definen y se llaman desde DebugMenu.cs.

Si bien algunos de estos métodos llaman a los métodos de Crashlytics y arrojan errores, la capacidad de Crashlytics para detectar estos errores no depende de llamar a esos métodos primero. En su lugar, los informes de fallas que se generan a partir de la detección automática de errores se mejorarán con la información que agregan estos métodos.

Abre DebugMenu.cs y, luego, busca los siguientes métodos:

Métodos para generar y anotar problemas de Crashlytics:

  • CrashNow
  • LogNonfatalError
  • LogStringsAndCrashNow
  • SetAndOverwriteCustomKeyThenCrash
  • SetLogsAndKeysBeforeANR

Métodos para registrar eventos de Analytics para facilitar la depuración:

  • LogProgressEventWithStringLiterals
  • LogIntScoreWithBuiltInEventAndParams

En pasos posteriores de este codelab, implementarás estos métodos y aprenderás cómo ayudan a abordar situaciones específicas que pueden ocurrir en el desarrollo de juegos.

6. Garantiza la entrega de informes de fallas en el desarrollo

Antes de comenzar a implementar estos métodos de depuración y ver cómo afectan a los informes de fallas, asegúrate de comprender cómo se informan los eventos a Crashlytics.

Para los proyectos de Unity, los eventos de falla y excepción del juego se escriben inmediatamente en el disco. En el caso de las excepciones no detectadas que no producen fallas en el juego (por ejemplo, excepciones de C# no detectadas en la lógica del juego), puedes hacer que el SDK de Crashlytics las informe como eventos irrecuperables mediante la configuración de la propiedad Crashlytics.ReportUncaughtExceptionsAsFatal en true, donde inicializas Crashlytics en tu proyecto de Unity. Estos eventos se informan a Crashlytics en tiempo real sin que el usuario final deba reiniciar el juego. Ten en cuenta que las fallas por errores en código nativo siempre se informan como eventos irrecuperables y se envían cuando un usuario final reinicia el juego.

Además, ten en cuenta las siguientes diferencias pequeñas, pero significativas, entre la forma en que los diferentes entornos de ejecución envían información de Crashlytics a Firebase:

Simulador de iOS:

  • La información de Crashlytics se informa solo si desconectas Xcode del simulador. Si se adjunta Xcode, detecta los errores de forma ascendente, lo que impide que se entregue la información.

Dispositivos móviles físicos (iOS y Android):

  • Específico de Android: Los ANR solo se informan en Android 11 y versiones posteriores. Los ANR y los eventos recuperables se informan en la próxima ejecución.

Editor de Unity:

Prueba hacer que tu juego falle con solo tocar un botón en CrashNow()

Después de configurar Crashlytics en tu juego, el SDK de Crashlytics registra automáticamente las fallas y las excepciones no detectadas, y las sube a Firebase para su análisis. Los informes se muestran en el panel de Crashlytics en Firebase console.

  1. Para demostrar que esto es automático, abre DebugMenu.cs y reemplaza el método CrashNow() de la siguiente manera:
    void CrashNow()
    {
        TestCrash();
    }
    
  2. Crea la app.
  3. (Solo para Android) Sube tus símbolos ejecutando el siguiente comando de Firebase CLI:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Presiona el botón Crash Now y continúa con el siguiente paso de este codelab para descubrir cómo ver e interpretar el informe de fallas.

7. Comprende los informes de problemas en Firebase console

Cuando se trata de ver tus informes de fallas, hay un poco más de información que debes saber para aprovecharlos al máximo. Cada uno de los métodos que escribas te mostrará cómo agregar diferentes tipos de información a los informes de Crashlytics.

  1. Presiona el botón Crash Now y, luego, reinicia la app.
  2. Ve al panel de Crashlytics. Desplázate hacia abajo hasta la tabla Problemas ubicada en la parte inferior del panel, en la que Crashlytics agrupa los eventos que tienen la misma causa raíz en “problemas”.
  3. Haz clic en el problema nuevo que aparece en la tabla Problemas. Cuando lo hagas, se mostrará el Resumen del evento sobre cada evento individual que se envió a Firebase.

    Deberías ver una captura de pantalla similar a la siguiente. Observa cómo el Resumen del evento destaca de forma destacada el seguimiento de pila de la llamada que generó la falla.40c96abe7f90c3aa.png

Metadatos adicionales

Otra pestaña útil es la pestaña Unity Metadata. Esta sección te informa sobre los atributos del dispositivo en el que ocurrió el evento, incluidas las características físicas, el modelo o las especificaciones de la CPU, y todo tipo de métricas de GPU.

En el siguiente ejemplo, la información de la pestaña podría resultar útil:
Imagina que el juego hace un uso intensivo de sombreadores para lograr una apariencia determinada, pero no todos los teléfonos tienen GPU capaces de renderizar esta función. La información de la pestaña Unity Metadata puede darte una mejor idea del hardware que debería probar tu app cuando decida qué funciones estarán disponibles automáticamente o se inhabilitarán por completo.

Si bien es posible que un error o una falla nunca ocurra en tu dispositivo, debido a la enorme diversidad de dispositivos Android disponibles, es útil comprender mejor los "hotspots" específicos de los dispositivos de tu público.

41d8d7feaa87454d.png

8. Lanza, captura y registra una excepción

A menudo, como desarrollador, incluso si tu código detecta y maneja adecuadamente una excepción de tiempo de ejecución, es bueno observar que ocurrió y en qué circunstancias. Crashlytics.LogException se puede usar con este propósito: enviar un evento de excepción a Firebase, de modo que puedas depurar el problema en Firebase console.

  1. En Assets/Hamster/Scripts/States/DebugMenu.cs, agrega lo siguiente a las sentencias using:
    // Import Firebase
    using Firebase.Crashlytics;
    
  2. Aún en DebugMenu.cs, reemplaza LogNonfatalError() de la siguiente manera:
    void LogNonfatalError()
    {
        try
        {
            throw new System.Exception($"Test exception thrown in {nameof(LogNonfatalError)}");
        }
        catch(System.Exception exception)
        {
            Crashlytics.LogException(exception);
        }
    }
    
  3. Crea la app.
  4. (Solo para Android) Sube tus símbolos ejecutando el siguiente comando de Firebase CLI:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  5. Presiona el botón Registrar error recuperable y, luego, reinicia la app.
  6. Ve al panel de Crashlytics. Deberías ver algo similar a lo que viste en el último paso de este codelab.
  7. Sin embargo, esta vez restringe el filtro Tipo de evento a Errores no graves para que solo se vean los errores recuperables, como el que acabas de registrar.
    a39ea8d9944cbbd9.png

9. Registra las cadenas en Crashlytics para comprender mejor el flujo de ejecución del programa

¿Alguna vez intentaste descubrir por qué una línea de código a la que se llama desde múltiples rutas, cientos o miles de veces por sesión, puede generar de repente una excepción o falla? Aunque sería bueno revisar el código en un IDE y observar los valores con más detalle, ¿qué sucede si esto ocurre solo entre un porcentaje extremadamente pequeño de tus usuarios? Y lo que es peor, ¿qué harías si no pudieras replicar esta falla sin importar lo que hagas?

En situaciones como esta, tener algo de contexto puede marcar una gran diferencia. Con Crashlytics.Log, puedes escribir el contexto que necesitas. Piensa en estos mensajes como pistas para tu yo futuro sobre lo que podría estar sucediendo.

Si bien los registros se pueden usar de muchas maneras, suelen ser más útiles para registrar situaciones en las que el orden o la ausencia de llamadas es un dato de vital importancia.

  1. En Assets/Hamster/Scripts/States/DebugMenu.cs, reemplaza LogStringsAndCrashNow() de la siguiente manera:
    void LogStringsAndCrashNow()
    {
        Crashlytics.Log($"This is the first of two descriptive strings in {nameof(LogStringsAndCrashNow)}");
        const bool RUN_OPTIONAL_PATH = false;
        if(RUN_OPTIONAL_PATH)
        {
            Crashlytics.Log(" As it stands, this log should not appear in your records because it will never be called.");
        }
        else
        {
            Crashlytics.Log(" A log that will simply inform you which path of logic was taken. Akin to print debugging.");
        }
        Crashlytics.Log($"This is the second of two descriptive strings in {nameof(LogStringsAndCrashNow)}");
        TestCrash();
    }
    
  2. Crea la app.
  3. (Solo para Android) Sube tus símbolos ejecutando el siguiente comando de Firebase CLI:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Presiona el botón Log Strings and Crash Now y, luego, reinicia la app.
  5. Vuelve al panel de Crashlytics y haz clic en el problema más reciente que aparece en la tabla Problemas. Una vez más, deberías ver algo similar a los problemas anteriores.
    7aabe103b8589cc7.png
  6. Sin embargo, si haces clic en la pestaña Registros en un Resumen del evento, obtendrás una vista como la siguiente:
    4e27aa407b7571cf.png

10. Escribe y reemplaza una clave personalizada

Supongamos que quieres comprender mejor una falla correspondiente a variables establecidas en una pequeña cantidad de valores o configuraciones. Sería bueno poder filtrar en cualquier momento determinado según la combinación de variables y posibles valores que estés observando.

Además de registrar strings arbitrarias, Crashlytics ofrece otra forma de depuración cuando es beneficioso conocer el estado exacto del programa cuando falló: las claves personalizadas.

Estos son pares clave-valor que puedes establecer para una sesión. A diferencia de los registros que se acumulan y son puramente aditivos, las claves se pueden reemplazar para reflejar solo el estado más reciente de una variable o condición.

Además de ser un registro del último estado registrado de tu programa, estas claves se pueden usar como filtros eficaces para los problemas de Crashlytics.

  1. En Assets/Hamster/Scripts/States/DebugMenu.cs, reemplaza SetAndOverwriteCustomKeyThenCrash() de la siguiente manera:
    void SetAndOverwriteCustomKeyThenCrash()
    {
        const string CURRENT_TIME_KEY = "Current Time";
        System.TimeSpan currentTime = System.DateTime.Now.TimeOfDay;
        Crashlytics.SetCustomKey(
            CURRENT_TIME_KEY,
            DayDivision.GetPartOfDay(currentTime).ToString() // Values must be strings
            );
    
        // Time Passes
        currentTime += DayDivision.DURATION_THAT_ENSURES_PHASE_CHANGE;
    
        Crashlytics.SetCustomKey(
            CURRENT_TIME_KEY,
            DayDivision.GetPartOfDay(currentTime).ToString()
            );
        TestCrash();
    }
    
  2. Crea la app.
  3. (Solo para Android) Sube tus símbolos ejecutando el siguiente comando de Firebase CLI:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Presiona el botón Establecer clave personalizada y falla y, luego, reinicia la app.
  5. Vuelve al panel de Crashlytics y haz clic en el problema más reciente que aparece en la tabla Problemas. Una vez más, deberías ver algo similar a los problemas anteriores.
  6. Sin embargo, esta vez, haz clic en la pestaña Claves en el Resumen del evento para ver el valor de las claves, incluido Current Time:
    8dbe1eb00566af98.png

¿Por qué se recomienda usar claves personalizadas en lugar de registros personalizados?

  • Los registros son buenos para almacenar datos secuenciales, pero las claves personalizadas son mejores si solo quieres el valor más reciente.
  • En Firebase console, puedes filtrar los problemas fácilmente según los valores de las claves en el cuadro de búsqueda de la tabla Problemas.

Sin embargo, al igual que los registros, las claves personalizadas tienen un límite. Crashlytics admite un máximo de 64 pares clave-valor. Cuando alcances este límite, no se guardarán los valores adicionales. Cada par clave-valor puede tener un tamaño de hasta 1 KB.

11. (Solo para Android) Usa claves y registros personalizados para comprender y diagnosticar un error de ANR

Una de las clases de problemas más difíciles de depurar para los desarrolladores de Android es el error Aplicación no responde (ANR). Los ANR se producen cuando una app no responde a una entrada durante más de 5 segundos. Si esto sucede, significa que la app dejó de funcionar o que funciona muy lentamente. Se muestra un diálogo a los usuarios y pueden elegir si quieren “Esperar” o “Cerrar la app”.

Los ANR representan una mala experiencia del usuario y, como se mencionó en el vínculo de ANR anterior, pueden afectar la visibilidad de tu app en Google Play Store. Debido a su complejidad y a que, a menudo, se deben a un código multiproceso con un comportamiento muy diferente en distintos modelos de teléfonos, reproducir los errores de ANR durante la depuración suele ser muy difícil, sino casi imposible. Por lo tanto, abordarlas de forma analítica y deductiva suele ser el mejor enfoque.

En este método, usaremos una combinación de Crashlytics.LogException, Crashlytics.Log y Crashlytics.SetCustomKey para complementar el registro automático de problemas y proporcionarnos más información.

  1. En Assets/Hamster/Scripts/States/DebugMenu.cs, reemplaza SetLogsAndKeysBeforeANR() de la siguiente manera:
    void SetLogsAndKeysBeforeANR()
    {
        System.Action<string,long> WaitAndRecord =
        (string methodName, long targetCallLength)=>
        {
            System.Diagnostics.Stopwatch stopWatch = new System.Diagnostics.Stopwatch();
            const string CURRENT_FUNCTION = "Current Async Function";
    
            // Initialize key and start timing
            Crashlytics.SetCustomKey(CURRENT_FUNCTION, methodName);
            stopWatch.Start();
    
            // The actual (simulated) work being timed.
            BusyWaitSimulator.WaitOnSimulatedBlockingWork(targetCallLength);
    
            // Stop timing
            stopWatch.Stop();
    
            if(stopWatch.ElapsedMilliseconds>=BusyWaitSimulator.EXTREME_DURATION_MILLIS)
            {
              Crashlytics.Log($"'{methodName}' is long enough to cause an ANR.");
            }
            else if(stopWatch.ElapsedMilliseconds>=BusyWaitSimulator.SEVERE_DURATION_MILLIS)
            {
              Crashlytics.Log($"'{methodName}' is long enough it may cause an ANR");
            }
        };
    
        WaitAndRecord("DoSafeWork",1000L);
        WaitAndRecord("DoSevereWork",BusyWaitSimulator.SEVERE_DURATION_MILLIS);
        WaitAndRecord("DoExtremeWork",2*BusyWaitSimulator.EXTREME_DURATION_MILLIS);
    }
    
  2. Crea la app.
  3. Ejecuta el siguiente comando de Firebase CLI para subir tus símbolos:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Presiona el botón Configurar registros y claves → ANR y, luego, reinicia la app.
  5. Regresa al panel de Crashlytics y haz clic en el problema nuevo de la tabla Problemas para ver el Resumen del evento. Si la llamada se realizó correctamente, deberías ver algo como esto:
    876c3cff7037bd07.png

    Como puedes ver, Firebase identificó la espera ocupada en el subproceso como el motivo principal por el que tu app activó un error de ANR.
  6. Si consultas los registros en la pestaña Registros de Resumen del evento, verás que el último método registrado como completado es DoSevereWork.
    5a4bec1cf06f6984.png

    Por el contrario, el último método que se muestra como iniciado es DoExtremeWork, lo que indica que el error de ANR ocurrió durante este método y que el juego se cerró antes de que pudiera registrar DoExtremeWork.

    89d86d5f598ecf3a.png

¿Por qué hacerlo?

  • Reproducir errores de ANR es increíblemente difícil, por lo que obtener información valiosa sobre el área de código y las métricas es increíblemente importante para descubrirlo de forma deductiva.
  • Con la información almacenada en las claves personalizadas, ahora sabes qué subproceso asíncrono tardó más tiempo en ejecutarse y cuáles corrían el riesgo de activar los errores de ANR. Este tipo de datos lógicos y numéricos relacionados te mostrará dónde es más necesario optimizar tu código.

12. Cómo intercalar eventos de Analytics para enriquecer aún más los informes

Los siguientes métodos también admiten llamadas desde el menú de depuración, pero en lugar de generar problemas por sí mismos, utilizan Google Analytics como otra fuente de información para comprender mejor el funcionamiento de tu juego.

A diferencia de los otros métodos que escribiste en este codelab, debes usar estos métodos en combinación con los demás. Llama a estos métodos (presionando el botón correspondiente en el menú de depuración) en el orden arbitrario que desees antes de ejecutar uno de los otros. Luego, cuando examines la información del problema específico de Crashlytics, verás un registro ordenado de los eventos de Analytics. Estos datos se pueden usar en un juego para comprender mejor una combinación de flujo del programa o entrada del usuario, según cómo hayas instrumentado tu app.

  1. En Assets/Hamster/Scripts/States/DebugMenu.cs, reemplaza las implementaciones existentes de los siguientes métodos:
    public void LogProgressEventWithStringLiterals()
    {
          Firebase.Analytics.FirebaseAnalytics.LogEvent("progress", "percent", 0.4f);
    }
    
    public void LogIntScoreWithBuiltInEventAndParams()
    {
          Firebase.Analytics.FirebaseAnalytics
            .LogEvent(
              Firebase.Analytics.FirebaseAnalytics.EventPostScore,
              Firebase.Analytics.FirebaseAnalytics.ParameterScore,
              42
            );
    }
    
  2. Compila e implementa tu juego y, luego, ingresa al menú de depuración.
  3. (Solo para Android) Sube tus símbolos ejecutando el siguiente comando de Firebase CLI:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Presiona al menos uno de los siguientes botones una o más veces para llamar a las funciones anteriores:
    • Evento de cadena de registro
    • Evento de acceso
  5. Presiona el botón Crash Now.
  6. Reinicia el juego para que suba el evento de falla a Firebase.
  7. Cuando registras varias secuencias arbitrarias de eventos de Analytics y, luego, haces que tu juego genere un evento a partir del cual Crashlytics crea un informe (como lo acabas de hacer), se agregan a la pestaña Registros de Resumen de eventos de Crashlytics de la siguiente manera:
    d3b16d78f76bfb04.png

13. De cara al futuro

Además, deberías tener una mejor base teórica para complementar los informes de fallas generados automáticamente. Esta nueva información te permite utilizar el estado actual, los registros de eventos pasados y los eventos existentes de Google Analytics para desglosar mejor la secuencia de eventos y la lógica que llevaron a su resultado.

Si tu app se orienta a Android 11 (nivel de API 30) o versiones posteriores, considera incorporar GWP-ASan, una función de asignación de memoria nativa útil para depurar fallas causadas por errores de la memoria nativa, como use-after-free y heap-buffer-overflow. Para aprovechar esta función de depuración, habilita GWP-ASan de forma explícita.

Próximos pasos

Continúa con el codelab Instrumenta tu juego de Unity con Remote Config, en el que aprenderás a usar Remote Config y A/B Testing en Unity.