Integración
// build.gradle (project)
plugins {
id("com.google.gms.google-services") version "4.4.1" apply false
id("com.google.firebase.crashlytics") version "3.0.1" apply false
}
// build.gradle (app)
plugins {
id("com.google.gms.google-services")
id("com.google.firebase.crashlytics")
}
dependencies {
implementation(platform("com.google.firebase:firebase-bom:33.0.0"))
implementation("com.google.firebase:firebase-crashlytics-ktx")
implementation("com.google.firebase:firebase-analytics-ktx")
}
Además necesitás el archivo google-services.json descargado desde la consola de Firebase, copiado en app/.
Crashlytics se integra con el mapping.txt automáticamenteEl plugin de Gradle sube el mapping.txt a Firebase en cada build de release. Los stack traces en la consola aparecen desobfuscados automáticamente — no necesitás hacerlo a mano.
Entender los reportes de crashes
La consola de Crashlytics agrupa los crashes por stack trace. Las métricas clave a monitorear:
- Crash-free users %: el porcentaje de usuarios que NO crashearon en las últimas 24h. La meta debería ser >99.5%.
- Velocity alerts: cuando un issue nuevo afecta a muchos usuarios rápidamente.
- Regresiones: issues que estaban cerrados y volvieron a aparecer en una nueva versión.
Para cada crash podés ver: stack trace completo, versión de Android, modelo de dispositivo, cantidad de usuarios afectados, y los eventos previos al crash (breadcrumbs).
Non-fatal exceptions
Los crashes fatales se reportan automáticamente. Pero hay errores que no crashean la app pero son importantes monitorear — por ejemplo, una respuesta inesperada de la API:
// Reportar una excepción non-fatal
try {
val respuesta = api.getProductos()
procesarRespuesta(respuesta)
} catch (e: IOException) {
// El usuario ve un mensaje de error, la app no crashea
mostrarError("Sin conexión")
// Pero queremos saber qué tan frecuente es este error en producción
Firebase.crashlytics.recordException(e)
}
// También podés reportar sin excepción — crear una sintética
fun reportarEstadoInesperado(mensaje: String) {
Firebase.crashlytics.recordException(
IllegalStateException("Estado inesperado: $mensaje")
)
}
// Útil para monitorear flujos que no deberían ocurrir:
when (estado) {
Estado.OK -> procesarOK()
Estado.ERROR -> procesarError()
else -> {
// Este caso no debería existir — quiero saberlo si pasa
Firebase.crashlytics.recordException(
IllegalStateException("Estado desconocido: $estado")
)
}
}
Custom keys — contexto del crash
Los custom keys agregan contexto al reporte. Cuando llega el crash, podés ver exactamente en qué estado estaba la app:
// Setear keys que aparecen en el reporte de cada crash
Firebase.crashlytics.setCustomKeys {
key("pantalla_actual", "ProductosFragment")
key("usuario_tipo", "admin")
key("modo_red", "wifi")
key("items_en_carrito", 3)
}
// Actualizar según el estado cambia
fun onNavegarA(destino: String) {
Firebase.crashlytics.setCustomKey("pantalla_actual", destino)
}
// Caso real: saber en qué paso de un flujo largo crasheó
fun procesarPago(paso: Int) {
Firebase.crashlytics.setCustomKey("paso_pago", paso)
// ... lógica del pago
}
Logs y breadcrumbs
Los logs en Crashlytics no aparecen en Logcat — se envían junto con el reporte del crash. Son los "pasos previos" al problema:
// Este log solo aparece en el reporte si hay un crash
Firebase.crashlytics.log("Usuario inició el flujo de checkout")
Firebase.crashlytics.log("Validación de formulario exitosa")
Firebase.crashlytics.log("Intentando procesar pago...")
// Si crashea acá, el reporte muestra estos tres logs como contexto
// Patrón recomendado: loggear en puntos clave del flujo
class CheckoutViewModel : ViewModel() {
fun iniciarCheckout() {
Firebase.crashlytics.log("iniciarCheckout()")
// ...
}
fun procesarPago(datos: DatosPago) {
Firebase.crashlytics.log("procesarPago: metodo=${datos.metodo}")
// ...
}
fun confirmarPedido(pedidoId: String) {
Firebase.crashlytics.log("confirmarPedido: id=$pedidoId")
// ...
}
}
No loggees datos sensiblesNo incluyas contraseñas, tokens, números de tarjeta ni datos personales en los logs de Crashlytics. Esos reportes los ven personas de tu equipo en la consola de Firebase.
Identificar usuarios
// Cuando el usuario inicia sesión, asociar su ID al crash
fun onLoginExitoso(usuario: Usuario) {
// Usar un ID interno, nunca email ni nombre real
Firebase.crashlytics.setUserId(usuario.id.toString())
}
// Cuando cierra sesión, limpiar
fun onLogout() {
Firebase.crashlytics.setUserId("")
}
No reportar crashes en debug
Por default Crashlytics no envía reportes en debug builds — necesita la inicialización correcta. Pero es bueno ser explícito:
// En Application.onCreate()
class MiApp : Application() {
override fun onCreate() {
super.onCreate()
// Solo inicializar Crashlytics en release
Firebase.crashlytics.setCrashlyticsCollectionEnabled(!BuildConfig.DEBUG)
}
}
Configurar alertas
En la consola de Firebase podés configurar alertas por email o Slack para:
- Nuevos issues que afecten a más de N usuarios
- Regresiones (issue que volvió a aparecer)
- Velocity alerts (crecimiento rápido de un crash)
- Aumento en el crash rate general de la app
Configurarlas desde Firebase Console → Crashlytics → Alerts. Son esenciales para detectar problemas en las primeras horas de un release.