sustituir Crashlytics por un recolector MetricKit que no sale del dispositivo

FirebaseCrashlytics se llevaba los informes de fallo a Google. Los crashes
ya llegan a Xcode Organizer por la vía de Apple, así que el sustituto no
tiene que enviar nada: DiagnosticsCollector se suscribe a MXMetricManager,
guarda los payloads de crash, cuelgue y escritura en disco como JSON en
Application Support/Diagnostics y ahí se quedan.

- Sin código de red. Retención de 5 informes, los ficheros se marcan como
  excluidos de backup (son ayuda de depuración, no datos del usuario).
- Arranque: AppDelegate llama a DiagnosticsCollector.shared.start() en
  lugar de FirebaseApp.configure() + MobileAds.shared.start().
- Ajustes → Acerca de: "Compartir diagnósticos", visible solo cuando hay
  algo recogido. Compartir es la única forma de que un informe salga del
  iPhone, y la decide el usuario. Cadenas nuevas en los 7 idiomas.

Un recolector que guarda y no enseña sería código muerto, y uno que sube
sería el problema de antes con otro nombre; por eso guarda en local y deja
el envío como acción explícita.

Closes #51

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F1u4K16xy7eQVtgsYNZ9Vn
This commit is contained in:
alexandrev-tibco
2026-09-18 16:09:45 +02:00
parent 7d2f605c16
commit 2380d37a9e
10 changed files with 178 additions and 0 deletions
@@ -881,11 +881,35 @@ struct SettingsView: View {
.foregroundStyle(.yellow)
}
}
// Only shown when MetricKit has actually left something behind.
// Sharing is the only way a report leaves the device.
if let latestReport = diagnosticReports.first {
Button {
viewModel.shareItem = SettingsViewModel.ShareItem(url: latestReport)
} label: {
HStack {
Text("Share Diagnostics")
Spacer()
Image(systemName: "square.and.arrow.up")
.font(.caption)
.foregroundStyle(.secondary)
}
}
}
} header: {
Text("About")
} footer: {
if !diagnosticReports.isEmpty {
Text("diagnostics_footer")
}
}
}
/// Crash/hang reports MetricKit left in the app container. They never leave
/// the device unless the user shares one from here.
private var diagnosticReports: [URL] { DiagnosticsCollector.shared.storedReports() }
// MARK: - Danger Zone Section
private var dangerZoneSection: some View {