Entenda as falhas de um jogo do Unity usando os recursos avançados do Crashlytics

1. Introdução

Neste codelab, você vai aprender a usar os recursos avançados do Crashlytics, que oferecem melhor visibilidade das falhas e das circunstâncias que podem ter causado essas falhas.

Você adicionará uma nova funcionalidade a um jogo de amostra, MechaHamster: Level Up with Firebase Edition. Este jogo de exemplo é uma nova versão do clássico jogo MechaHamster do Firebase que remove a maioria das funcionalidades integradas do Firebase, oferecendo a chance de implementar novos usos do Firebase no lugar deles.

Você vai adicionar um menu de depuração ao jogo. Esse menu de depuração chama os métodos que você vai criar e permite usar as diferentes funcionalidades do Crashlytics. Esses métodos mostram como fazer anotações nos relatórios automáticos de erros com chaves e registros personalizados, erros não fatais e muito mais.

Depois de criar o jogo, você vai usar o menu de depuração e inspecionar os resultados para entender a visão única que eles oferecem sobre como o jogo é executado no mundo real.

O que você vai aprender

  • Os tipos de erros detectados automaticamente pelo Crashlytics.
  • Outros erros que podem ser propositalmente registrados.
  • Como adicionar mais informações a esses erros para torná-los mais fáceis de entender.

Pré-requisitos

  • Unity (versão mínima recomendada de 2019 ou mais recente) com um dos seguintes itens ou ambos:
    • Suporte ao build do iOS
    • Suporte ao build do Android
  • (Somente para Android) A CLI do Firebase (usada para fazer upload de símbolos para relatórios de erros)

2. Configurar o ambiente de desenvolvimento

As seções a seguir descrevem como fazer o download do código do Level Up com o Firebase e abri-lo no Unity.

O jogo de exemplo Level Up with Firebase é usado por vários outros codelabs do Firebase e do Unity. Portanto, talvez você já tenha concluído as tarefas desta seção. Se esse for o caso, vá diretamente para a última etapa desta página: "Adicionar SDKs do Firebase para Unity".

Fazer o download do código

Clone o repositório do GitHub deste codelab na linha de comando:

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

Se você não tiver o git instalado, faça o download do repositório como um arquivo ZIP (link em inglês).

Abra Level Up with Firebase no editor do Unity.

  1. Inicie o Unity Hub e, na guia Projects, clique na seta suspensa ao lado de Open.
  2. Clique em Adicionar projeto do disco.
  3. Navegue até o diretório que contém o código e clique em OK.
  4. Se solicitado, selecione uma versão do editor Unity para usar e a plataforma de destino (Android ou iOS).
  5. Clique no nome do projeto, level-up-with-firebase, para que ele seja aberto no editor do Unity.
  6. Caso o editor não abra automaticamente, abra MainGameScene em Recursos > Hamster na guia Project do editor do Unity.
    ff4ea3f3c0d29379.png

Para mais informações sobre como instalar e usar o Unity, consulte Como trabalhar no Unity.

3. Adicionar o Firebase ao seu projeto do Unity

Criar um projeto do Firebase

  1. No Console do Firebase, clique em Adicionar projeto.
  2. Para criar um novo projeto, digite o nome dele.
    Isso também definirá o ID do projeto (exibido abaixo do nome do projeto) como algo baseado no nome do projeto. Também é possível clicar no ícone editar no ID do projeto para personalizá-lo ainda mais.
  3. Se solicitado, leia e aceite os Termos do Firebase.
  4. Clique em Continuar.
  5. Selecione a opção Ativar o Google Analytics para este projeto e clique em Continuar.
  6. Selecione uma conta existente do Google Analytics para usar ou selecione Criar uma nova conta.
  7. Clique em Criar projeto.
  8. Quando o projeto estiver pronto, clique em Continuar.

Registrar o app no Firebase

  1. Ainda no Console do Firebase, no centro da página de visão geral do projeto, clique no ícone do Unity para iniciar o fluxo de trabalho de configuração ou, se você já adicionou um app ao seu projeto do Firebase, clique em Adicionar app para exibir as opções da plataforma.
  2. Selecione para registrar os destinos de build para Apple (iOS) e Android.
  3. Insira os IDs específicos da plataforma do seu projeto do Unity. Para este codelab, insira o seguinte:
  4. (Opcional) Digite os apelidos específicos da plataforma do seu projeto do Unity.
  5. Clique em Registrar app e prossiga para a seção Fazer o download do arquivo de configuração.

Adicionar arquivos de configuração do Firebase

Depois de clicar em Registrar app, você receberá uma solicitação para fazer o download de dois arquivos de configuração (um para cada destino de build). Seu projeto do Unity precisa dos metadados do Firebase nesses arquivos para se conectar ao Firebase.

  1. Faça download dos dois arquivos de configuração disponíveis:
    • Para Apple (iOS): faça o download de GoogleService-Info.plist.
    • Para Android: faça o download do google-services.json.
  2. Abra a janela Project do seu projeto do Unity e mova os dois arquivos de configuração para a pasta Assets.
  3. De volta ao fluxo de trabalho de configuração no Console do Firebase, clique em Próximo e prossiga para Adicionar SDKs do Firebase para Unity.

Adicionar SDKs do Firebase para Unity

  1. Clique em Fazer o download do SDK do Firebase para Unity no Console do Firebase.
  2. Descompacte o SDK em um local prático.
  3. No seu projeto aberto do Unity, acesse Assets > Importar pacote > Pacote personalizado.
  4. Na caixa de diálogo Import package, acesse o diretório que contém o SDK descompactado, selecione FirebaseAnalytics.unitypackage e clique em Open.
  5. Na caixa de diálogo Import Unity Package exibida, clique em Import.
  6. Repita as etapas anteriores para importar FirebaseCrashlytics.unitypackage.
  7. Volte ao Console do Firebase e, no fluxo de trabalho de configuração, clique em Próxima.

Para mais informações sobre como adicionar SDKs do Firebase a projetos do Unity, consulte Outras opções de instalação do Unity.

4. Configurar o Crashlytics no seu projeto do Unity

Para usar o Crashlytics em projetos do Unity, é necessário seguir mais algumas etapas de configuração. Você vai precisar inicializar o SDK. Além disso, será necessário fazer upload dos seus símbolos para que você possa ver stack traces simbolizados no Console do Firebase, além de forçar uma falha de teste para garantir que o Firebase esteja recebendo os eventos de falha.

Inicializar o SDK do Crashlytics

  1. Em Assets/Hamster/Scripts/MainGame.cs, adicione as seguintes instruções using:
    using Firebase.Crashlytics;
    using Firebase.Extensions;
    
    O primeiro módulo permite usar métodos do SDK do Crashlytics, e o segundo contém algumas extensões para a API C# Tasks. Sem as duas instruções using, o código a seguir não funcionará.
  2. Ainda no MainGame.cs, adicione a inicialização do Firebase ao método Start() atual chamando InitializeFirebaseAndStartGame():
    void Start()
    {
      Screen.SetResolution(Screen.width / 2, Screen.height / 2, true);
      InitializeFirebaseAndStartGame();
    }
    
  3. Mais uma vez, em MainGame.cs, encontre InitializeFirebaseAndStartGame(), declare uma variável de app e substitua a implementação do método da seguinte forma:
    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 a lógica de inicialização aqui impede a interação do jogador antes que as dependências do Firebase sejam inicializadas.

Os benefícios e efeitos de informar exceções não processadas como fatais são discutidos nas Perguntas frequentes do Crashlytics.

Crie seu projeto e faça upload de símbolos

As etapas para criar e fazer upload de símbolos são diferentes para apps iOS e Android.

iOS+ (plataforma Apple)

  1. Na caixa de diálogo Build Settings, exporte seu projeto para um espaço de trabalho do Xcode.
  2. Crie seu app.
    Para plataformas Apple, o plug-in do Editor do Firebase para Unity configura automaticamente seu projeto Xcode para gerar e fazer upload de um arquivo de símbolos compatível com Crashlytics para os servidores do Firebase em cada build. Essas informações de símbolos são necessárias para exibir stack traces simbolizados no painel do Crashlytics.

Android

  1. (somente durante a configuração inicial, não para cada build) Configure seu build:
    1. Crie uma nova pasta chamada Builds na raiz do diretório do projeto (ou seja, como irmão do diretório Assets) e crie uma subpasta chamada Android.
    2. Em Arquivo > Configurações da versão > Configurações do player > Configuração, defina o back-end de scripts como IL2CPP.
      • O IL2CPP geralmente faz com que os builds sejam menores e tenham melhor desempenho.
      • O IL2CPP também é a ÚNICA opção disponível no iOS. Se você selecioná-lo aqui, as duas plataformas terão melhor paridade e simplificarão as diferenças de depuração entre elas (se você optar por criar as duas).
  2. Crie o app. Em Arquivo > Configurações da versão, faça o seguinte:
    1. Verifique se a opção Criar símbolos.zip está marcada ou, se um menu suspenso aparecer, selecione Depuração.
    2. Crie seu APK diretamente do Unity Editor na subpasta Builds/Android que você acabou de criar.
  3. Quando seu build estiver concluído, será necessário gerar um arquivo de símbolo compatível com Crashlytics e fazer upload dele para os servidores do Firebase. Essas informações de símbolos são necessárias para exibir stack traces simbolizados para falhas da biblioteca nativa no painel do Crashlytics.

    Gere e faça upload desse arquivo de símbolos executando o seguinte comando da CLI do Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
    • FIREBASE_APP_ID: o ID do app Android no Firebase (não o nome do pacote). Encontre esse valor no arquivo google-services.json que você transferiu por download anteriormente. É o valor mobilesdk_app_id.
      Exemplo de ID do app Android do Firebase: 1:567383003300:android:17104a2ced0c9b9b
    • PATH/TO/SYMBOLS: o caminho do arquivo de símbolo compactado gerado no diretório Builds/Android quando o build termina (por exemplo: Builds/Android/myapp-1.0-v100.symbols.zip).

Forçar uma falha de teste para concluir a configuração

Para concluir a configuração do Crashlytics e ver os dados iniciais no painel dele no Console do Firebase, é necessário forçar uma falha de teste.

  1. Em MainGameScene, encontre o EmptyObjectGameObject na seção Hierarchy do editor, adicione o script a seguir a ele e salve a cena. Esse script vai causar uma falha no teste alguns segundos depois de executar o 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. Crie o app e faça upload das informações de símbolos após a conclusão do build.
    • iOS: o plug-in do Editor do Firebase para Unity configura automaticamente seu projeto Xcode para fazer upload do arquivo de símbolo.
    • Android: execute o comando crashlytics:symbols:upload da CLI do Firebase para fazer upload do arquivo de símbolo.
  3. Execute o app. Quando o app estiver em execução, observe o registro do dispositivo e aguarde a exceção ser acionada no CrashlyticsTester.
    • iOS: veja os registros no painel inferior do Xcode.
    • Android: confira os registros executando o seguinte comando no terminal: adb logcat.
  4. Acesse o painel do Crashlytics para conferir a exceção. Ele vai aparecer na tabela Problemas, na parte de baixo do painel. Mais adiante no codelab, você aprenderá mais sobre como analisar esses relatórios.
  5. Depois de confirmar que o evento foi enviado para o Crashlytics, selecione o EmptyObject GameObject ao qual ele foi anexado, remova apenas o componente CrashlyticsTester e salve a cena para restaurá-la à condição original.

5. Ativar e entender o menu de depuração

Até agora, você adicionou o Crashlytics ao seu projeto do Unity, finalizou a configuração e confirmou que o SDK do Crashlytics está fazendo upload de eventos para o Firebase. Agora você vai criar um menu no seu projeto do Unity que demonstra como usar as funcionalidades mais avançadas do Crashlytics no seu jogo. O projeto do Unity Level Up with Firebase já tem um menu de depuração oculto que ficará visível e você escreverá a funcionalidade para ele.

Ativar o menu de depuração

O botão para acessar o menu de depuração existe no seu projeto do Unity, mas não está ativado no momento. É necessário ativar o botão para acessá-lo no prefab MainMenu:

  1. No editor do Unity, abra o prefab chamado MainMenu.4148538cbe9f36c5.png
  2. Na hierarquia do prefab, encontre e selecione o subobjeto desativado DebugMenuButton.816f8f9366280f6c.png
  3. Ative DebugMenuButton marcando a caixa no canto superior esquerdo à esquerda do campo de texto que contém DebugMenuButton.8a8089d2b4886da2.png
  4. Salve o prefab.
  5. Execute o jogo no editor ou no seu dispositivo. O menu deve estar acessível.

Visualizar e entender os corpos dos métodos do menu de depuração

Mais adiante neste codelab, você vai criar corpos de métodos para alguns métodos do Crashlytics de depuração pré-configurados. No entanto, no projeto do Unity Level Up com Firebase, os métodos são definidos e chamados em DebugMenu.cs.

Embora alguns desses métodos chamem os métodos do Crashlytics e lancem erros, a capacidade do Crashlytics para detectar esses erros não depende de chamar esses métodos primeiro. Em vez disso, os relatórios de erros gerados com a detecção automática de erros serão aprimorados pelas informações adicionadas por esses métodos.

Abra DebugMenu.cs e encontre os seguintes métodos:

Métodos para gerar e anotar problemas do Crashlytics:

  • CrashNow
  • LogNonfatalError
  • LogStringsAndCrashNow
  • SetAndOverwriteCustomKeyThenCrash
  • SetLogsAndKeysBeforeANR

Métodos para registrar eventos do Analytics para ajudar na depuração:

  • LogProgressEventWithStringLiterals
  • LogIntScoreWithBuiltInEventAndParams

Nas próximas etapas deste codelab, você vai implementar esses métodos e aprender como eles ajudam a lidar com situações específicas que podem ocorrer no desenvolvimento de jogos.

6. Garantir a entrega de relatórios de erros em desenvolvimento

Antes de começar a implementar esses métodos de depuração e ver como eles afetam os relatórios de erros, entenda como os eventos são informados ao Crashlytics.

Para projetos do Unity, os eventos de falha e exceção do jogo são gravados imediatamente no disco. Para exceções não identificadas que não causam falhas no jogo (por exemplo, exceções de C# não capturadas na lógica do jogo), você pode fazer com que o SDK do Crashlytics as relate como eventos fatais definindo a propriedade Crashlytics.ReportUncaughtExceptionsAsFatal como true, em que inicializa o Crashlytics no seu projeto do Unity. Esses eventos são informados ao Crashlytics em tempo real, sem que o usuário final precise reiniciar o jogo. As falhas nativas são sempre relatadas como eventos fatais e enviadas quando um usuário final reinicia o jogo.

Além disso, esteja ciente das seguintes diferenças pequenas, mas significativas, entre como os diferentes ambientes de execução enviam informações do Crashlytics para o Firebase:

Simulador do iOS:

  • As informações do Crashlytics serão relatadas apenas se você desanexar o Xcode do simulador. Se o Xcode estiver anexado, ele vai capturar os erros upstream, impedindo a entrega de informações.

Dispositivos físicos móveis (Android e iOS):

  • Específicos do Android: os ANRs são informados apenas no Android 11 e versões mais recentes. ANRs e eventos não fatais são informados na próxima execução.

Editor do Unity:

Teste a falha do jogo com o toque de um botão em CrashNow()

Depois que o Crashlytics é configurado no seu jogo, o SDK do Crashlytics registra automaticamente as falhas e exceções não identificadas e as envia ao Firebase para análise. Os relatórios são exibidos no painel do Crashlytics no Console do Firebase.

  1. Para demonstrar que isso é mesmo automático: abra DebugMenu.cs e substitua o método CrashNow() da seguinte maneira:
    void CrashNow()
    {
        TestCrash();
    }
    
  2. Compile seu app.
  3. (Somente Android) Faça upload dos seus símbolos executando o seguinte comando da CLI do Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Toque no botão Crash Now e avance para a próxima etapa deste codelab para saber como acessar e interpretar o relatório de erros.

7. Entender os relatórios de problemas no Console do Firebase

Quando se trata de visualizar seus relatórios de erros, há um pouco mais de que você precisa saber sobre como aproveitá-los ao máximo. Cada um dos métodos vai mostrar como adicionar diferentes tipos de informações aos relatórios do Crashlytics.

  1. Toque no botão Crash Now e reinicie o app.
  2. Acesse o painel do Crashlytics. Role para baixo até a tabela Issues na parte de baixo do painel, onde o Crashlytics agrupa eventos que têm a mesma causa raiz em "problemas".
  3. Clique no novo problema listado na tabela Problemas. Isso exibe o Resumo do evento sobre cada evento individual que foi enviado ao Firebase.

    Você verá algo parecido com a captura de tela a seguir. Observe como o Resumo do evento destaca o stack trace da chamada que causou a falha.40c96abe7f90c3aa.png

Metadados adicionais

Outra guia útil é a Unity Metadata. Esta seção informa os atributos do dispositivo em que o evento ocorreu, incluindo recursos físicos, o modelo/especificações da CPU e todos os tipos de métricas da GPU.

Confira um exemplo em que as informações desta guia podem ser úteis:
imagine que seu jogo usa muitos sombreadores para conseguir um determinado visual, mas nem todos os smartphones têm GPUs capazes de renderizar esse recurso. As informações na guia Unity Metadata (link em inglês) dão uma ideia melhor de qual hardware seu app precisa testar ao decidir quais recursos disponibilizar ou desativar automaticamente.

Embora um bug ou falha nunca aconteça no seu dispositivo, devido à enorme diversidade de dispositivos Android disponíveis, é útil entender melhor os "pontos de acesso" específicos. dos dispositivos do seu público-alvo.

41d8d7feaa87454d.png

8. Gerar, capturar e registrar uma exceção

Muitas vezes, como desenvolvedor, mesmo que seu código capture e processe adequadamente uma exceção de tempo de execução, é bom observar que ela ocorreu e em quais circunstâncias. Crashlytics.LogException pode ser usado exatamente para essa finalidade: enviar um evento de exceção ao Firebase para que você possa depurar o problema no Console do Firebase.

  1. Em Assets/Hamster/Scripts/States/DebugMenu.cs, anexe o seguinte às instruções using:
    // Import Firebase
    using Firebase.Crashlytics;
    
  2. Ainda em DebugMenu.cs, substitua LogNonfatalError() desta maneira:
    void LogNonfatalError()
    {
        try
        {
            throw new System.Exception($"Test exception thrown in {nameof(LogNonfatalError)}");
        }
        catch(System.Exception exception)
        {
            Crashlytics.LogException(exception);
        }
    }
    
  3. Compile seu app.
  4. (Somente Android) Faça upload dos seus símbolos executando o seguinte comando da CLI do Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  5. Toque no botão Log Nonfatal Error e reinicie o app.
  6. Acesse o painel do Crashlytics e encontre algo parecido com o que você viu na última etapa deste codelab.
  7. Desta vez, restrinja o filtro Tipo de evento a Não fatais para ver apenas erros não fatais, como o que acabou de ser registrado.
    a39ea8d9944cbbd9.png

9. Registrar strings no Crashlytics para entender melhor o fluxo de execução do programa

Você já tentou descobrir por que uma linha de código que é chamada de vários caminhos, centenas ou até milhares de vezes por sessão, pode gerar de repente uma exceção ou falha? Pode ser bom analisar o código em um ambiente de desenvolvimento integrado e analisar os valores mais de perto. Mas e se isso acontecer somente entre uma porcentagem muito pequena de usuários? Pior ainda, o que você faria se não pudesse replicar essa falha, não importa o que faça?

Em situações como essa, ter um pouco de contexto pode fazer toda a diferença. Com o Crashlytics.Log, é possível escrever o contexto necessário. Pense nessas mensagens como dicas para você no futuro sobre o que pode estar acontecendo.

Embora os registros possam ser usados de várias maneiras, eles geralmente são mais úteis para registrar situações em que a ordem e/ou a ausência de chamadas é uma informação de vital importância.

  1. Em Assets/Hamster/Scripts/States/DebugMenu.cs, substitua LogStringsAndCrashNow() desta forma:
    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. Compile seu app.
  3. (Somente Android) Faça upload dos seus símbolos executando o seguinte comando da CLI do Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Toque no botão Log Strings and Crash Now e reinicie o app.
  5. Volte para o painel do Crashlytics e clique no problema mais recente listado na tabela Problemas. Mais uma vez, você verá algo semelhante aos problemas anteriores.
    7aabe103b8589cc7.png
  6. No entanto, se você clicar na guia Registros em um Resumo do evento, terá uma exibição como esta:
    4e27aa407b7571cf.png

10. Gravar e substituir uma chave personalizada

Digamos que você queira entender melhor uma falha correspondente a variáveis definidas com um pequeno número de valores ou configurações. Pode ser bom poder filtrar, com base na combinação de variáveis e possíveis valores que você está analisando, a qualquer momento.

Além de registrar strings arbitrárias, o Crashlytics oferece outra forma de depuração quando é vantajoso saber o estado exato do programa enquanto ele falhou: chaves personalizadas.

São pares de chave-valor que você pode definir para uma sessão. Ao contrário dos registros que se acumulam e são puramente aditivos, as chaves podem ser substituídas para refletir apenas o status mais recente de uma variável ou condição.

Além de serem um livro-razão do último estado registrado do seu programa, essas chaves podem então ser usadas como filtros poderosos para problemas do Crashlytics.

  1. Em Assets/Hamster/Scripts/States/DebugMenu.cs, substitua SetAndOverwriteCustomKeyThenCrash() desta forma:
    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. Compile seu app.
  3. (Somente Android) Faça upload dos seus símbolos executando o seguinte comando da CLI do Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Toque no botão Definir chave personalizada e falha e reinicie o app.
  5. Volte para o painel do Crashlytics e clique no problema mais recente listado na tabela Problemas. Mais uma vez, você verá algo semelhante aos problemas anteriores.
  6. Desta vez, clique na guia Chaves no Resumo do evento para conferir o valor das chaves, incluindo Current Time:
    7dbe1eb00566af98.png

Por que você usaria chaves personalizadas em vez de registros personalizados?

  • Os registros são bons para armazenar dados sequenciais, mas as chaves personalizadas são melhores se você quiser apenas o valor mais recente.
  • No Console do Firebase, é possível filtrar facilmente os problemas pelos valores das chaves na caixa de pesquisa da tabela Problemas.

No entanto, assim como nos registros, as chaves personalizadas têm um limite. O Crashlytics aceita no máximo 64 pares de chave-valor. Ao atingir esse limite, os valores adicionais não serão salvos. Cada par de chave-valor pode ter até 1 KB de tamanho.

11. (Somente Android) Usar chaves e registros personalizados para entender e diagnosticar um ANR

Uma das classes de problemas mais difíceis de depurar para desenvolvedores Android é o erro O app não está respondendo (ANR). Os ANRs ocorrem quando um app não responde à entrada por mais de cinco segundos. Se isso acontecer, o app travou ou está muito lento. Uma caixa de diálogo é mostrada aos usuários, e eles podem escolher se querem "Esperar" ou "Fechar aplicativo".

ANRs são uma experiência ruim para o usuário e, como mencionado no link de ANR acima, podem afetar a capacidade de descoberta do seu app na Google Play Store. Devido à complexidade e geralmente causadas por código com várias linhas de execução com comportamento muito diferente em modelos de smartphone distintos, reproduzir ANRs durante a depuração costuma ser muito difícil, se não quase impossível. Assim, abordá-los de forma analítica e dedutiva é geralmente a melhor abordagem.

Nesse método, usaremos uma combinação de Crashlytics.LogException, Crashlytics.Log e Crashlytics.SetCustomKey para complementar o registro automático de problemas e fornecer mais informações.

  1. Em Assets/Hamster/Scripts/States/DebugMenu.cs, substitua SetLogsAndKeysBeforeANR() desta forma:
    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. Compile seu app.
  3. Faça upload dos símbolos executando o seguinte comando da CLI do Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Toque no botão Definir registros e chaves → ANR e reinicie o app.
  5. Volte ao painel do Crashlytics e clique no novo problema na tabela Problemas para ver o Resumo do evento. Se a chamada tiver sido feita corretamente, você verá algo assim:
    876c3cff7037bd07.png

    Como você pode ver, o Firebase identificou a espera ocupada na linha de execução como o principal motivo pelo qual seu app acionou um ANR.
  6. Na guia Registros de Resumo do evento, você vai notar que o último método registrado como concluído é DoSevereWork.
    5a4bec1cf06f6984.png

    Por outro lado, o último método listado como inicial é DoExtremeWork, que indica que o ANR ocorreu durante esse método e o jogo foi fechado antes de registrar DoExtremeWork.

    89d86d5f598ecf3a.png

Por que fazer isso?

  • Reproduzir ANRs é muito difícil. Por isso, conseguir informações detalhadas sobre a área e as métricas do código é muito importante para a descoberta de forma dedutiva.
  • Com as informações armazenadas nas chaves personalizadas, agora você sabe qual linha de execução assíncrona levou mais tempo para ser executada e quais corriam perigo de acionar ANRs. Esse tipo de dados lógicos e numéricos relacionados mostrará onde em seu código é mais necessário otimizar.

12. Como intercalar eventos do Analytics para enriquecer ainda mais os relatórios

Os métodos a seguir também podem ser chamados no menu de depuração. No entanto, em vez de gerar problemas, eles usam o Google Analytics como outra fonte de informações para entender melhor o funcionamento do seu jogo.

Ao contrário dos outros métodos que você criou neste codelab, use-os junto com os outros. Chame esses métodos (pressionando o botão correspondente no menu de depuração) em qualquer ordem arbitrária que você quiser antes de executar um dos outros. Em seguida, ao examinar as informações do problema específico do Crashlytics, você verá um registro ordenado de eventos do Analytics. Esses dados podem ser usados em um jogo para entender melhor uma combinação do fluxo do programa ou da entrada do usuário, dependendo de como você instrumentou seu aplicativo.

  1. Em Assets/Hamster/Scripts/States/DebugMenu.cs, substitua as implementações atuais dos seguintes 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. Crie e implante seu jogo e acesse o Menu de depuração.
  3. (Somente Android) Faça upload dos seus símbolos executando o seguinte comando da CLI do Firebase:
    firebase crashlytics:symbols:upload --app=<FIREBASE_APP_ID> <PATH/TO/SYMBOLS>
    
  4. Pressione pelo menos um dos botões a seguir uma ou mais vezes para chamar as funções acima:
    • Registrar evento de string
    • Registrar evento de login
  5. Pressione o botão Crash Now.
  6. Reinicie o jogo para que ele faça upload do evento com falha no Firebase.
  7. Quando você registra várias sequências arbitrárias de eventos do Analytics e faz seu jogo gerar um evento do qual o Crashlytics cria um relatório (como você acabou de fazer), elas são adicionadas à guia Registros do Resumo do evento do Crashlytics, desta forma:
    d3b16d78f76bfb04.png

13. O futuro

Com isso, você terá uma base teórica melhor para complementar os relatórios de erros gerados automaticamente. Com essas novas informações, você pode usar o estado atual, os registros de eventos anteriores e os eventos atuais do Google Analytics para detalhar melhor a sequência de eventos e a lógica que levaram ao resultado.

Caso o app seja destinado ao Android 11 (nível 30 da API) ou versões mais recentes, considere incorporar o GWP-ASan, um recurso de alocação de memória nativo útil para depurar falhas causadas por erros de memória nativa, como bugs use-after-free e heap-buffer-overflow. Para usar esse recurso de depuração, ative o GWP-ASan explicitamente.

Próximas etapas

Prossiga para o codelab Instrumentar seu jogo Unity com a Configuração remota, em que você aprenderá a usar a Configuração remota e o Teste A/B no Unity.