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 brindarán una mejor visibilidad de las fallas y las circunstancias que podrían haberlas causado.

Agregarás nuevas funciones a un juego de muestra, MechaHamster: Sube de nivel con Firebase Edition. Este juego de muestra es una versión nueva del juego clásico de Firebase MechaHamster que quita la mayor parte de su funcionalidad integrada 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 ejecutar las diferentes funcionalidades 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 en el entorno.

Qué aprenderás

  • Los tipos de errores que Crashlytics detecta automáticamente.
  • Errores adicionales que pueden registrarse intencionalmente.
  • 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 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 en Android) Firebase CLI (que se usa para subir símbolos en 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 instalado Git, puedes descargar el repositorio como un archivo ZIP.

Abre Level Up with 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 haz clic en OK.
  4. Si se te solicita, selecciona la versión del editor de Unity que quieres usar y tu plataforma de segmentación (Android o iOS).
  5. Haz clic en el nombre del proyecto, level-up-with-firebase, para que el proyecto se abra 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 cómo instalar y usar 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.
    Esto también establecerá el ID del proyecto (que se muestra debajo del nombre) en un valor basado en el nombre del proyecto. 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 la cuenta de Google Analytics existente que deseas usar o elige la opción Crear una cuenta nueva para crear una.
  7. Haz clic en Crear proyecto.
  8. Una vez que 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 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 la plataforma del 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 la plataforma.

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

Agrega los SDK de Firebase para Unity

  1. En Firebase console, haz clic en Descargar el SDK de Firebase Unity.
  2. Descomprime el SDK en la ubicación que prefieras.
  3. Abre tu 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 Open.
  5. En el diálogo Import Unity Package que aparece, haz clic en Import.
  6. Repite los pasos anteriores para importar FirebaseCrashlytics.unitypackage.
  7. Regresa 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. Deberás inicializar el SDK. Sin embargo, también deberás subir tus símbolos de modo que puedas ver seguimientos de pila simbolizados en Firebase console y deberás 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 código que aparece a continuación no funcionará.
  2. Aún en MainGame.cs, llama a InitializeFirebaseAndStartGame():
    void Start()
    {
      Screen.SetResolution(Screen.width / 2, Screen.height / 2, true);
      InitializeFirebaseAndStartGame();
    }
    
    para agregar la inicialización de Firebase al método Start() existente.
  3. Una vez más, en MainGame.cs, busca InitializeFirebaseAndStartGame(), declara una variable de app y, luego, 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 irrecuperables 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 en las apps para iOS y 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 tu proyecto de Xcode automáticamente para generar y subir un archivo de símbolos compatible con Crashlytics a los servidores de Firebase de cada compilación. Esta información de símbolos es obligatoria para ver los 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 nueva carpeta llamada Builds en la raíz del directorio de tu proyecto (es decir, como un elemento del mismo nivel del directorio Assets) y, a continuación, 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 si la seleccionas aquí, las dos plataformas tendrán una mejor paridad y simplificarán las diferencias de depuración entre las dos (si eliges compilar ambas).
  2. Compila tu app. En File > Build Settings, completa lo siguiente:
    1. Asegúrate de que la opción CreateSymbol.zip esté marcada (o, si aparece un menú desplegable, selecciona Debugging).
    2. Compila tu APK directamente desde Unity Editor en la subcarpeta Builds/Android que acabas de crear.
  3. Una vez finalizada la compilación, debes generar un archivo de símbolos compatible con Crashlytics y subirlo a los servidores de Firebase. Esta información de símbolos es obligatoria para ver los seguimientos de pila simbolizados de las fallas de las 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 para Android de Firebase (no el nombre del paquete). Busca este valor en el archivo google-services.json que descargaste antes. Es el valor mobilesdk_app_id.
      Ejemplo de ID de la app para Android de Firebase: 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 finalizar la configuración de Crashlytics y ver los datos iniciales en el panel de Crashlytics de Firebase console, debes forzar una falla de prueba.

  1. En MainGameScene, busca EmptyObject GameObject en el editor 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 después de que termine el proceso.
    • iOS: El complemento Firebase Unity Editor configura tu proyecto de Xcode automáticamente para subir tu 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. Luego, revisa 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 comando adb logcat en la terminal para ver los registros.
  4. Visita el panel de Crashlytics para ver la excepción. Lo verás en la tabla Problemas ubicada en la parte inferior del panel. Más adelante en el codelab, obtendrás más información para 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, luego, guarda la escena para restablecerla 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 en el que se demostrará cómo usar funciones de Crashlytics más avanzadas en tu juego. El proyecto de Unity Sube de nivel con Firebase ya tiene un menú de depuración oculto que estarás visible y escribirás la funcionalidad.

Habilitar el menú Depuración

El botón para acceder al menú de depuración existe en tu proyecto de Unity, pero no está habilitado actualmente. 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 la 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 deberías poder acceder al menú.

Obtener una vista previa y comprender los cuerpos del método para el menú Debug

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 Sube de nivel con Firebase, los métodos se definen en DebugMenu.cs y se llaman desde allí.

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 generados a partir de la detección automática de errores se mejorarán con la información que agreguen 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 los 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. Garantizar la entrega de informes de fallas durante el desarrollo

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

En el caso de los proyectos de Unity, los eventos de fallas y excepciones del juego se escriben inmediatamente en el disco. En el caso de las excepciones no detectadas que no fallan 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 configurando la propiedad Crashlytics.ReportUncaughtExceptionsAsFatal como true, donde inicializas Crashlytics en tu proyecto de Unity. Estos eventos se informan a Crashlytics en tiempo real sin necesidad de que el usuario final reinicie 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 se desconecta Xcode del simulador. Si se adjunta Xcode, detecta los errores en sentido ascendente, lo que impide la entrega de información.

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

  • Elementos específicos para Android: Los ANR solo se informan en Android 11 y versiones posteriores. Los ANR y eventos recuperables se informarán en la próxima ejecución.

Editor de Unity:

Prueba hacer que el 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. Además, los informes se muestran en el panel de Crashlytics en Firebase console.

  1. Para demostrar que esto es realmente automático, abre DebugMenu.cs y, luego, reemplaza el método CrashNow() de la siguiente manera:
    void CrashNow()
    {
        TestCrash();
    }
    
  2. Crea la app.
  3. (Solo para Android) 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 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 que debes saber para aprovecharlos al máximo. En cada uno de los métodos que escribas, se 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. Esta acción muestra el resumen del evento sobre cada evento individual que se envió a Firebase.

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

Metadatos adicionales

Otra pestaña útil es la de Unity Metadata. En esta sección, encontrarás información sobre los atributos del dispositivo en el que ocurrió el evento, incluidas las funciones físicas, el modelo o las especificaciones de la CPU y todo tipo de métricas de GPU.

Este es un ejemplo en el que la información de esta pestaña podría ser útil:
Imagina que tu juego hace un uso intensivo de sombreadores para lograr un aspecto determinado, pero no todos los teléfonos tienen GPU que pueden renderizar esta función. La información de la pestaña Unity Metadata puede darte una mejor idea del hardware para el que se debe probar tu app a la hora de decidir qué funciones estarán disponibles o inhabilitarán automáticamente por completo.

Si bien es posible que nunca se produzca un error o una falla en tu dispositivo, debido a la enorme diversidad de dispositivos Android en el mundo, nos ayuda a comprender mejor los "hotspots" específicos de los dispositivos de tu público.

41d8d7feaa87454d.png

8. Cómo arrojar, capturar y registrar una excepción

A menudo, como desarrollador, incluso si tu código detecta y maneja correctamente una excepción de tiempo de ejecución, es bueno tener en cuenta que se produjo y en qué circunstancias. Crashlytics.LogException se puede usar con este propósito exacto para enviar un evento de excepción a Firebase, de modo que puedas depurar aún más 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) Ejecuta el siguiente comando de Firebase CLI para subir tus símbolos:
    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 No fatales para que solo se vean los errores recuperables, como el que acabas de registrar.
    39ea8d9944cbbd9.png

9. Registra 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 que se llama desde múltiples rutas de acceso, cientos o miles de veces por sesión, puede generar repentinamente una excepción o falla? Si bien podría ser bueno revisar el código en un IDE y observar los valores con más detalle, ¿qué sucede si esto sucede solo en un porcentaje muy pequeño de los usuarios? Y lo que es peor, ¿qué harías si no pudieras replicar esta falla sin importar lo que hagas?

En situaciones como esta, contar con cierto 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, por lo general, son más útiles para registrar situaciones en las que el orden o la ausencia de las 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) 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 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.
    8aabe103b8589cc7.png
  6. Sin embargo, si haces clic en la pestaña Registros de 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 las variables configuradas en una pequeña cantidad de valores o parámetros de configuración. Sería bueno poder filtrar, en función de la combinación de variables y valores posibles que estás observando, en cualquier momento.

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

Estos son pares clave-valor que puedes configurar 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) 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 Set Custom Key and Crash 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 del Resumen del evento para ver el valor de las claves, incluido Current Time:
    7dbe1eb00566af98.png

¿Por qué querrías usar claves personalizadas en lugar de registros personalizados?

  • Los registros son buenos para almacenar datos secuenciales, pero las claves personalizadas son mejores si solo deseas el valor más reciente.
  • En Firebase console, puedes filtrar fácilmente los problemas por 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. Usa claves y registros personalizados para comprender y diagnosticar un error de ANR (solo para Android)

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 errores de ANR se producen cuando una app no responde a las entradas durante más de 5 segundos. Si esto ocurre, significa que la app se tildó o que funciona con lentitud. Se muestra un diálogo a los usuarios en el que pueden elegir si quieren "Esperar" o "Cerrar la app".

Los errores de 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 suelen deberse a un código multiproceso con un comportamiento muy diferente en distintos modelos de teléfonos, reproducir ANR durante la depuración suele ser muy difícil o casi imposible. Por lo tanto, abordarlos de manera 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 Set Logs And Keys → ANR y, luego, reinicia la app.
  5. Vuelve 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 lo siguiente:
    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 observas 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 aparece como inicio es DoExtremeWork, que indica que el error de ANR se produjo durante este método y que el juego se cerró antes de que se registrara DoExtremeWork.

    89d86d5f598ecf3a.png

¿Por qué hacerlo?

  • Reproducir ANR es muy difícil, por lo que es muy importante obtener información valiosa sobre el área de código y las métricas para averiguarlo de manera deductiva.
  • Con la información almacenada en las claves personalizadas, ahora sabes qué subproceso asíncrono tardó más en ejecutarse y cuáles estuvieron en riesgo de activar errores de ANR. Este tipo de datos lógicos y numéricos relacionados le mostrará en qué parte de su código es más necesario realizar una optimización.

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

También se puede llamar a los siguientes métodos desde el menú de depuración, pero, en lugar de generar problemas por sí mismos, usan 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 (presiona 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 del flujo del programa o la entrada del usuario, según cómo instrumentes 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. Luego, ingresa al menú de depuración.
  3. (Solo para Android) 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 al menos uno de los siguientes botones una o más veces para llamar a las funciones anteriores:
    • Registra evento de cadena
    • 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 cree un informe (como acabas de hacer), se agregan a la pestaña Registros del Resumen del evento de Crashlytics de la siguiente manera:
    d3b16d78f76bfb04.png

13. De cara al futuro

Y con eso, deberías tener una mejor base teórica sobre la cual complementar tus informes de fallas generados automáticamente. Esta nueva información te permite usar el estado actual, los registros de eventos anteriores y existentes de Google Analytics para desglosar mejor la secuencia de eventos y la lógica que condujo al resultado.

Si tu app se orienta a Android 11 (nivel de API 30) o versiones posteriores, te recomendamos incorporar GWP-ASan, una función de asignación de memoria nativa útil para depurar fallas causadas por errores de memoria nativa, como errores 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 Cómo instrumentar tu juego de Unity con Remote Config, en el que aprenderás a usar Remote Config y A/B Testing en Unity.