O MAUI usa o SDK .NET, que tem como alvo o netstandard2.0 e é o mesmo pacote que uma aplicação WPF, WinForms, Avalonia ou de consola usaria; vê medir uma aplicação para saberes o que reporta. O que é específico do MAUI é onde o arrancas, onde pões a fila dele, e como os ecrãs ficam com nome.

O código-fonte, e uma aplicação de secretária de demonstração que se reporta a si mesma, estão em skomi-sdk-dotnet.

Um cliente, para toda a vida da aplicação

Regista-o no MauiProgram.cs para que a aplicação tenha exatamente um:

builder.Services.AddSingleton(_ => new SkomiClient(new SkomiOptions
{
    AppId = Guid.Parse("your-app-id"),          // from My Apps in Skomi
    AppVersion = AppInfo.Current.VersionString,
    StoragePath = FileSystem.Current.AppDataDirectory,
}));

O AppVersion assume de origem a versão do assembly de entrada, que no MAUI não é a versão que entregaste a uma loja. O AppInfo.Current.VersionString é.

O StoragePath decide onde vive a fila para quando não há rede. O FileSystem.Current.AppDataDirectory é privado da aplicação em todos os alvos do MAUI e sobrevive a uma atualização, coisa que o caminho de origem dos dados locais da aplicação não faz de forma fiável em telemóveis.

⚠ Descarta-o ao desligar. Isso para o temporizador e faz uma última tentativa limitada de entrega; o que não for agora fica em disco e vai na execução seguinte. Se o registaste como singleton, o contentor de injeção descarta-o por ti quando o anfitrião desliga, mas uma aplicação MAUI é muitas vezes morta em vez de desligada, que é a razão de a fila existir de todo.

Dá nome aos teus ecrãs

skomi.Screen("checkout/review", new Dictionary<string, object?> { ["tier"] = "gold" });

Não há recolha automática de nomes de página: a classe de uma página é como o teu código chama a um ecrã, não como lhe chamarias num relatório. O lugar natural no MAUI é um único handler na navegação:

Shell.Current.Navigated += (_, e) =>
    skomi.Screen(e.Current.Location.OriginalString.Trim('/'));

É um ponto de partida e não uma regra: as cadeias de rota só dão nomes legíveis se as tuas rotas forem legíveis.

Erros

try
{
    await CheckoutAsync();
}
catch (Exception ex)
{
    skomi.CaptureError(ex, fatal: false, screenName: "checkout/review");
    ShowRetry();
}

Os erros são agrupados por tipo em vez de por mensagem, porque uma mensagem transporta identificadores e valores que tornam única cada ocorrência.

⚠ Isto não é um sistema de relatórios de falhas. Grava os erros que lhe entregas e as exceções geridas que consegue ver; uma falha nativa no Android ou no iOS leva o processo com ela antes de se conseguir escrever seja o que for. Mantém os relatórios de falhas da própria loja, ou o Crashlytics ou o Sentry, para essas; o que a Skomi acrescenta é uma taxa de sessões sem falhas ao lado dos números das tuas versões, e os erros que escolheste reportar.

Também não há envio de ficheiros de mapeamento, portanto uma pilha de uma versão minificada chega tal como foi lançada.

Nunca lança exceções para o teu código

Todos os métodos públicos engolem e reportam através do OnError, que é silencioso de origem. Isso é o certo para uma aplicação entregue e o errado enquanto estás a integrar:

OnError = (ex, stage) => Debug.WriteLine($"Skomi {stage}: {ex}"),

À espera do consentimento

new SkomiOptions { AppId = id, Enabled = false }

Com Enabled = false não se grava nada e não se envia nada, e é assim que se respeita quem recusou. Não é um interruptor para ligar mais tarde: para esperar pelo consentimento, cria o cliente só depois de alguém concordar.

Confirma que está a funcionar

Corre a aplicação, muda entre duas páginas, e olha para o teu painel. Se não chegar nada, define primeiro o OnError: um identificador de aplicação da aplicação errada e um cliente que nunca foi descartado são as duas causas habituais, e sem ele as duas são silenciosas.