import 'package:carrier_info/carrier_info.dart'; import 'package:flutter/foundation.dart'; import 'country_code_source.dart'; /// Ermittelt den ISO-Ländercode aus SIM-/Netzwerk-Informationen via /// `carrier_info` (`docs/plan.md`, Abschnitt 2 + 3: primäre, offline /// verfügbare Quelle). /// /// **Android:** Priorität liegt auf `networkCountryIso` des aktuell /// eingebuchten Mobilfunknetzes (aus `telephonyInfo`) – nicht auf dem /// Heimatland der SIM. Genau dieses Netz wickelt einen Notruf ab, ändert /// sich also korrekt bei Roaming (siehe Plan, Zeile "Bei Konflikt ... /// gewinnt automatisch die SIM-Quelle"). Fällt zurück auf /// `isoCountryCode` (SIM-Ausgabeland laut Telephony API) und zuletzt auf /// `countryIso` aus `subscriptionsInfo`. /// /// **iOS:** Apple hat `CTCarrier` ab iOS 16 deprecated (`docs/plan.md`, /// Abschnitt 9 – verbleibendes Risiko). `carrier_info` liefert auf iOS /// 16+ für `isoCountryCode` verlässlich `null` zurück (siehe Paket-Doku /// `iOS_16_DEPRECATION_NOTICE.md`). Das ist eine bekannte Plattform- /// Einschränkung, kein Bug: Diese Quelle liefert dann einfach `null`, /// wodurch `LocationService` automatisch auf GPS/Reverse-Geocoding /// zurückfällt. /// /// Alle Plugin-Aufrufe sind defensiv in try/catch gekapselt: Auf /// Emulatoren, Geräten ohne SIM oder bei Plugin-Fehlern kann /// `carrier_info` werfen oder leere/`null`-Werte liefern – in jedem Fall /// liefert [resolve] dann `null`, nie eine Exception. class SimCountryCodeSource implements CountryCodeSource { const SimCountryCodeSource(); @override Future resolve() async { try { switch (defaultTargetPlatform) { case TargetPlatform.android: return await _resolveAndroid(); case TargetPlatform.iOS: return await _resolveIos(); default: // Kein Mobilfunk-Stack auf Desktop/Web-Zielen (auch wenn diese // App laut Scope nur Android/iOS unterstützt, siehe Plan // Abschnitt 7 – defensiv trotzdem abgedeckt). return null; } } catch (_) { return null; } } Future _resolveAndroid() async { final info = await CarrierInfo.getAndroidInfo(); if (info == null) return null; for (final telephony in info.telephonyInfo) { final code = _normalize(telephony.networkCountryIso); if (code != null) return code; } for (final telephony in info.telephonyInfo) { final code = _normalize(telephony.isoCountryCode); if (code != null) return code; } for (final subscription in info.subscriptionsInfo) { final code = _normalize(subscription.countryIso); if (code != null) return code; } return null; } Future _resolveIos() async { final info = await CarrierInfo.getIosInfo(); for (final carrier in info.carrierData) { final code = _normalize(carrier.isoCountryCode); if (code != null) return code; } return null; } String? _normalize(String? code) { final trimmed = code?.trim(); if (trimmed == null || trimmed.isEmpty) return null; return trimmed.toUpperCase(); } }