MAUI usa el SDK de .NET, que apunta a netstandard2.0 y es el mismo paquete que usaría una aplicación WPF, WinForms, Avalonia o de consola; véase medir una aplicación para lo que informa. Lo propio de MAUI es dónde lo arrancas, dónde pones su cola, y cómo reciben sus nombres las pantallas.

El código fuente, y una aplicación de escritorio de demostración que se mide a sí misma, están en skomi-sdk-dotnet.

Un cliente, para toda la vida de la aplicación

Regístralo en MauiProgram.cs para que la aplicación tenga exactamente uno:

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,
}));

AppVersion vale por defecto la versión del ensamblado de entrada, que en MAUI no es la versión que publicaste en una tienda. AppInfo.Current.VersionString sí lo es.

StoragePath decide dónde vive la cola sin conexión. FileSystem.Current.AppDataDirectory es privado de la aplicación en todos los destinos de MAUI y sobrevive a una actualización, cosa que la ruta de datos locales de aplicación por defecto no hace de forma fiable en móvil.

⚠ Libéralo al apagar. Eso detiene el temporizador y hace un último intento acotado de entrega; lo que no salga ahora está en el disco y sale en la siguiente ejecución. Si lo registraste como singleton, el contenedor de inyección lo libera por ti cuando el anfitrión se apaga, pero a una aplicación MAUI se la mata más a menudo de lo que se la apaga, que es la razón misma por la que existe la cola.

Nombra tus pantallas

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

No hay captura automática de nombres de página: una clase de página es lo que tu código llama una pantalla, no lo que tú llamarías así en un informe. El lugar natural en MAUI es un manejador en la navegación:

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

Es un punto de partida y no una regla: las cadenas de ruta hacen nombres legibles solo si tus rutas son legibles.

Errores

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

Los errores se agrupan por tipo y no por mensaje, porque un mensaje lleva identificadores e importes que hacen única cada ocurrencia.

⚠ Esto no es un sistema de informes de fallos. Registra los errores que le entregas y las excepciones administradas que puede ver; un fallo nativo en Android o iOS se lleva el proceso por delante antes de que se pueda escribir nada. Mantén los informes de fallos de la propia tienda, o Crashlytics o Sentry, para esos; lo que añade Skomi es una tasa de sesiones sin fallos junto a tus cifras de versión, y los errores que elegiste informar.

Tampoco hay subida de archivo de correspondencia, así que una pila de llamadas de una compilación de producción minificada llega tal como se levantó.

Nunca lanza una excepción dentro de tu código

Todos los métodos públicos se lo tragan e informan por OnError, que es silencioso por defecto. Eso es lo correcto para una aplicación publicada, y no mientras estás integrando:

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

Esperar el consentimiento

new SkomiOptions { AppId = id, Enabled = false }

Enabled = false no registra nada y no manda nada, y es la forma de respetar a quien se ha negado. No es un interruptor para activar después: para esperar el consentimiento, crea el cliente solo cuando alguien haya dado su acuerdo.

Comprobar que funciona

Ejecuta la aplicación, muévete entre dos páginas, y mira tu panel. Si no llega nada, pon primero OnError: un identificador de aplicación de la aplicación equivocada y un cliente que nunca se liberó son las dos causas habituales, y las dos son silenciosas sin él.