🔥

Firebase Crashlytics — NutriTrack

Guía de integración completa · Android & iOS · Beta Launch Ready

Firebase Crashlytics Android Kotlin iOS SwiftUI
2
Plataformas integradas
3
Crashes detectados pre-beta
100%
Cobertura crash automática
<5 min
Tiempo de primer reporte
1

Crashes Pre-Beta — Mapa de prioridad

Análisis
⚠️
Se detectaron 3 crashes críticos en testing interno antes del lanzamiento beta. Crashlytics permitirá trazarlos en producción con stack traces simbolizados y contexto de usuario.
Error Plataforma Módulo Frecuencia Severidad
OutOfMemoryError Android FoodListFragment → Firestore ~1 de cada 12 cargas Critical
EXC_BAD_ACCESS iOS CameraScanner → AVFoundation Reproducible en iPhone 13 mini Critical
NullPointerException Android UserProfileViewModel Cold start ocasional Medium
2

Android — Configuración Gradle (Kotlin DSL)

Android
ℹ️
Asegúrate de tener google-services.json en app/ antes de proceder. Obtenerlo con: npx firebase-tools apps:sdkconfig ANDROID <App-ID>
📄 build.gradle.kts (project)
📄 build.gradle.kts (app)
build.gradle.kts — nivel proyecto Kotlin DSL
// NutriTrack — build.gradle.kts (project level)
plugins {
    // ... plugins existentes
    id("com.google.gms.google-services") version "4.4.2" apply false
    id("com.google.firebase.crashlytics") version "3.0.3" apply false
}
build.gradle.kts — nivel app module Kotlin DSL
// NutriTrack — app/build.gradle.kts
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
    id("com.google.gms.google-services")        // Google Services
    id("com.google.firebase.crashlytics")        // ← Crashlytics plugin
}

dependencies {
    // Firebase BoM — gestiona versiones automáticamente
    implementation(platform("com.google.firebase:firebase-bom:33.7.0"))

    // Crashlytics + Analytics (recomendado conjunto)
    implementation("com.google.firebase:firebase-crashlytics-ktx")
    implementation("com.google.firebase:firebase-analytics-ktx")
}
🔐
NDK crashes (OutOfMemoryError): Añade también firebase-crashlytics-ndk y activa nativeSymbolUploadEnabled = true en el buildType release para simbolizar los crash reports nativos de Firestore.
Custom keys para rastrear el crash de FoodList Kotlin
import com.google.firebase.crashlytics.FirebaseCrashlytics

class FoodListFragment : Fragment() {

    private fun loadFoodList() {
        val crashlytics = FirebaseCrashlytics.getInstance()

        // Context personalizado antes de operaciones de riesgo
        crashlytics.setCustomKey("food_list_page", currentPage)
        crashlytics.setCustomKey("user_plan", "premium")
        crashlytics.setCustomKey("firestore_collection", "alimentos_es")
        crashlytics.log("Iniciando carga de alimentos — página $currentPage")

        // Identificar usuario en el reporte
        crashlytics.setUserId(viewModel.currentUserId)

        db.collection("alimentos_es")
            .limit(50)
            .get()
            .addOnFailureListener { exception ->
                // Reportar excepción no-fatal con contexto
                crashlytics.recordException(exception)
                showErrorState()
            }
    }
}
3

iOS — Swift Package Manager + dSYM Upload

iOS SwiftUI
1

Registrar la app iOS en Firebase

Bundle ID: com.cultivaia.nutritrack — crea el registro y descarga GoogleService-Info.plist, añádelo al Xcode target.

2

Instalar SDK via Swift Package Manager

Repo: https://github.com/firebase/firebase-ios-sdk.git — añade el producto FirebaseCrashlytics

3

Configurar Debug Information Format

Build Settings → DWARF with dSYM File en Debug y Release. Requerido para simbolizar EXC_BAD_ACCESS.

4

Añadir Run Script Phase (dSYM upload)

Build Phases → New Run Script Phase con el script de upload de Crashlytics.

NutriTrackApp.swift — inicialización Firebase Swift
import SwiftUI
import FirebaseCore
import FirebaseCrashlytics

@main
struct NutriTrackApp: App {
    init() {
        FirebaseApp.configure()
        // Habilitar recolección (por defecto true en release)
        Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true)
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}
CameraScannerView.swift — custom keys para EXC_BAD_ACCESS Swift
import AVFoundation
import FirebaseCrashlytics

class CameraScannerViewModel: ObservableObject {

    func startCapture(deviceModel: String) {
        let crashlytics = Crashlytics.crashlytics()

        // Keys de contexto para reproducir EXC_BAD_ACCESS
        crashlytics.setCustomValue(deviceModel, forKey: "device_model")
        crashlytics.setCustomValue(UIDevice.current.systemVersion, forKey: "ios_version")
        crashlytics.setCustomValue("barcode_scanner", forKey: "active_feature")
        crashlytics.log("Iniciando AVCaptureSession — dispositivo: \(deviceModel)")

        do {
            let session = AVCaptureSession()
            // ... setup cámara
        } catch {
            // Non-fatal: fallo al acceder a cámara
            crashlytics.record(error: error)
            showCameraPermissionAlert()
        }
    }

    func setCurrentUser(_ userId: String, plan: String) {
        Crashlytics.crashlytics().setUserID(userId)
        Crashlytics.crashlytics().setCustomValue(plan, forKey: "subscription_plan")
    }
}
Build Phase — dSYM upload script Shell
# Añadir en Build Phases → New Run Script Phase
${BUILD_DIR%/Build/*}/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/run

# Input Files:
# $(SRCROOT)/$(BUILT_PRODUCTS_DIR)/$(INFOPLIST_PATH)
# $(DWARF_DSYM_FOLDER_PATH)/$(DWARF_DSYM_FILE_NAME)/Contents/Resources/DWARF/$(TARGET_NAME)
4

Verificación — Forzar Test Crash

Requerido
🧪
Importante: Elimina el código de test crash antes del lanzamiento en TestFlight/Play Console. Este paso es solo para verificar que el reporting funciona correctamente.

ANDROID — Test crash

MainActivity.kt Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // ⚠️ SOLO PARA TEST — eliminar
    Handler(Looper.getMainLooper())
        .postDelayed({
            throw RuntimeException("NutriTrack Test Crash")
        }, 3000)
}

iOS — Test crash

AppDelegate.swift Swift
func application(_ application: UIApplication,
    didFinishLaunchingWithOptions...) -> Bool {
    FirebaseApp.configure()
    // ⚠️ SOLO PARA TEST — eliminar
    DispatchQueue.main.asyncAfter(
        deadline: .now() + 3) {
        fatalError("NutriTrack Test Crash")
    }
    return true
}
1

Ejecutar app y esperar el crash

La app crasheará a los 3 segundos. iOS: desconectar el debugger de Xcode antes de lanzar.

2

Relanzar la app

El SDK envía el reporte a Firebase en el siguiente arranque (no en el crash inmediato).

3

Verificar en Firebase Console

DevOps & Engagement → Crashlytics. El crash aparece en ~2-5 minutos con stack trace simbolizado.

4

Eliminar el código de test

Confirmar recepción del reporte y quitar el bloque de fatalError / RuntimeException del código.

5

Beta Launch Checklist — NutriTrack

Pre-Release
  • Firebase project nutritrack-prod creado y configurado google-services.json y GoogleService-Info.plist en su lugar correcto
  • SDK Crashlytics añadido via BoM (Android) y SPM (iOS) firebase-crashlytics-ktx + FirebaseCrashlytics instalados
  • Test crash ejecutado y verificado en ambas plataformas Reportes visibles en Firebase Console con stack traces correctos
  • !
    Custom keys configurados en módulos críticos (FoodList, CameraScanner) Pendiente: añadir keys en UserProfileViewModel para rastrear NPE
  • !
    NDK crash reporting activo para OutOfMemoryError Pendiente: nativeSymbolUploadEnabled = true en buildType release
  • User IDs vinculados para correlación con soporte setUserId() llamado tras autenticación en ambas plataformas
  • Alertas configuradas en Firebase Console (crash-free users < 99%) Email notifications al equipo de dev cuando crash rate supere umbral
  • Eliminar código de test crash del build de producción Verificar que no hay fatalError() ni RuntimeException("Test") en main branch