Hallo Zusammen,
hat jemand schon mal in iOS18 mit CLMonitor eine Region überwacht?
Mit iOS17 hat bei mir die Überwachung einer Region wunderbar funktioniert, nach dem Update auf einem realen Gerät auf iOS18 regt sich die App im Hintergrund nicht mehr.
Gruß Marvin
Alles anzeigen
hat jemand schon mal in iOS18 mit CLMonitor eine Region überwacht?
Mit iOS17 hat bei mir die Überwachung einer Region wunderbar funktioniert, nach dem Update auf einem realen Gerät auf iOS18 regt sich die App im Hintergrund nicht mehr.
Gruß Marvin
Quellcode
- @Observable
- class LocationManager: NSObject, @preconcurrency CLLocationManagerDelegate, @unchecked Sendable {
- static let shared = LocationManager()
- // DispatchQueue für synchrone Zugriffe
- private let queue = DispatchQueue(label: "com.example.locationManager", attributes: .concurrent)
- let locationManager: CLLocationManager = CLLocationManager()
- var region: MKCoordinateRegion = MKCoordinateRegion()
- var error: LocationError? = nil
- var monitor: CLMonitor?
- var authorizationStatus : CLAuthorizationStatus = .authorizedAlways
- var authorizationFault: Bool = false
- var badge: Int = 0
- var userLocationData: UserLocationData?
- /** Für Authentifizierungssitzungen und Benachrichtigungen*/
- private var authSession: CLServiceSession?
- private let notificationCenter = UNUserNotificationCenter.current()
- private var notificationContent = UNMutableNotificationContent()
- /** Adressvariablen*/
- var strasse : String = ""
- var hausnummer : String = ""
- var plz : String = ""
- var ort : String = ""
- var ortsteil : String = ""
- var landKreis : String = ""
- var bundesland : String = ""
- var land : String = ""
- var isoCountryCode : String = ""
- var zeitzone : TimeZone?
- var detectedIBeacons: [iBeacon] = []
- var isScanning: Bool = false
- override init() {
- super.init()
- self.locationManager.delegate = self
- self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
- self.locationManager.distanceFilter = kCLDistanceFilterNone
- self.locationManager.allowsBackgroundLocationUpdates = true
- self.locationManager.showsBackgroundLocationIndicator = true
- self.locationManager.activityType = .fitness
- /** Benachrichtigung konfigurieren*/
- notificationContent.title = "Location monitoring inactive"
- notificationContent.body = "Can't receive condition events while not in the foreground"
- Task {
- try await notificationCenter.requestAuthorization(options: [.badge])
- }
- }
- func requestUserAuthorization() async throws {
- queue.async(flags: .barrier) {
- self.locationManager.requestAlwaysAuthorization()
- }
- }
- // Implementiere die startAuthSession-Funktion
- func startAuthSession() {
- Task {
- print("Listening to session diagnostics")
- authSession = CLServiceSession(authorization: .always, fullAccuracyPurposeKey: "monitor")
- for try await diagnostics in authSession!.diagnostics {
- // Speichern der letzten Diagnosedaten
- // lastDiagnosticUpdate = diagnostics (optional, falls verwendet)
- print("Diadnostics: \(diagnostics)")
- let notification = UNNotificationRequest(identifier: "com.example.mynotification", content: notificationContent, trigger: nil)
- if diagnostics.insufficientlyInUse {
- try await notificationCenter.add(notification)
- }
- }
- }
- }
- // Funktion zum Stoppen der Authentifizierungssitzung
- func stopAuthSession() {
- Task {
- print("Stopping session diagnostics")
- authSession?.invalidate() // Sitzungsinvalidation
- authSession = nil
- }
- }
- func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
- queue.async(flags: .barrier) {
- switch self.locationManager.authorizationStatus {
- case .notDetermined:
- self.locationManager.requestWhenInUseAuthorization()
- case .authorizedAlways, .authorizedWhenInUse:
- self.locationManager.requestLocation()
- case .denied:
- self.error = .authorizationDenied
- case .restricted:
- self.error = .authorizationRestricted
- @unknown default:
- break
- }
- }
- }
- func checkLocationServicesAuthorizationOnAppStart(logbook: Bool) async {
- let authorizationStatus = LocationAuthorizationStatus(locationManager.authorizationStatus)
- switch authorizationStatus {
- case .notDetermined:
- print("Der Standortautorisierungsstatus wurde nicht ermittelt.")
- authorizationFault = true
- case .authorizedAlways:
- print("Der Standortautorisierungsstatus ist immer autorisiert.")
- authorizationFault = false
- case .authorizedWhenInUse:
- print("Der Standortautorisierungsstatus ist bei Verwendung autorisiert.")
- authorizationFault = true
- case .denied:
- print("Der Status der Standortautorisierung ist verweigert.")
- authorizationFault = true
- case .restricted:
- print("Der Standortautorisierungsstatus ist eingeschränkt.")
- authorizationFault = true
- }
- }
- func startUpdateLocation() {
- queue.async(flags: .barrier) {
- self.locationManager.startUpdatingLocation()
- }
- }
- func stopUpdateLocation() {
- queue.async(flags: .barrier) {
- self.locationManager.stopUpdatingLocation()
- }
- }
- func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
- queue.async(flags: .barrier) {
- guard let location = locations.last else { return }
- let updatedData = UserLocationData(
- userLocation: location,
- coordinates: location.coordinate,
- lat: location.coordinate.latitude,
- lon: location.coordinate.longitude,
- speed: location.speed,
- speedAccuracy: location.speedAccuracy,
- altitude: location.altitude,
- floorLevel: location.floor?.level ?? 0,
- floor: location.floor,
- horizontalAccuracy: location.horizontalAccuracy,
- verticalAccuracy: location.verticalAccuracy,
- timestamp: location.timestamp,
- courseAccuracy: location.courseAccuracy,
- course: location.course
- )
- self.userLocationData = updatedData
- }
- }
- func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
- queue.async(flags: .barrier) {
- print("Error \(error.localizedDescription)")
- self.locationManager.stopUpdatingLocation()
- self.locationManager.stopUpdatingHeading()
- if let clError = error as? CLError {
- switch clError.code {
- case .locationUnknown:
- self.error = .unknownLocation
- case .denied:
- self.error = .accessDenied
- case .network:
- self.error = .network
- default:
- self.error = .operationFailed
- }
- }
- }
- }
- func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
- print("Region: DetermineState \(region.identifier)")
- }
- func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
- print("Region: Enter \(region.identifier)")
- }
- func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
- print("Region: Exit \(region.identifier)")
- }
- func locationManager(_ manager: CLLocationManager, didVisit visit: CLVisit) {
- print("Region: Date\(visit.arrivalDate)")
- }
- func locationManager(_ manager: CLLocationManager, didFailRangingFor beaconConstraint: CLBeaconIdentityConstraint, error: Error) {
- print("Failed ranging beacons: \(error.localizedDescription)")
- }
- func startMonitoringCLMonitor(minVerzoegerung: TimeInterval) async {
- // Initialisiere den Monitor, wenn er noch nicht existiert
- if monitor == nil {
- monitor = await CLMonitor("StechuhrPro")
- }
- self.startAuthSession()
- do {
- // Durchlaufe die Events und fange Fehler ab
- for try await event in await monitor!.events {
- startUpdateLocation()
- let identifier = event.identifier
- let name = await checkOrteNameByUUID(id: UUID(uuidString: identifier)!)
- switch event.state {
- case .satisfied:
- await handleSatisfiedState(for: identifier, with: name, minVerzoegerung: minVerzoegerung)
- case .unsatisfied:
- await handleUnsatisfiedState(for: identifier, with: name, minVerzoegerung: minVerzoegerung)
- case .unknown:
- print("Status unbekannt \(event.identifier) Date/Time: \(Date())")
- await addLogbookEntry(category: .location, ereignis: "Der Status der Region \(name) ist unbekannt")
- case .unmonitored:
- print("Region nicht überwacht \(event.identifier) Date/Time: \(Date())")
- await addLogbookEntry(category: .location, ereignis: "Region \(name) wird nicht überwacht")
- @unknown default:
- print("Unbekannter Zustand")
- }
- stopUpdateLocation()
- }
- } catch {
- print("Fehler beim Empfangen der Events: \(error.localizedDescription)")
- // Hier kannst du den Fehler protokollieren oder spezifisch behandeln
- }
- }
- }