Last active
December 16, 2017 16:33
-
-
Save moaible/d857d2b522e7ad9a3941fee7bc45a9cc to your computer and use it in GitHub Desktop.
Geofence.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import CoreLocation | |
| import CoreMotion | |
| struct Geofence { | |
| typealias Degreese = Double | |
| typealias Radius = Double | |
| var identifier: String | |
| var radius: Radius | |
| var latitude: Degreese | |
| var longitude: Degreese | |
| } | |
| extension Geofence { | |
| enum PermissionMode { | |
| case always | |
| case whenInAppUse | |
| } | |
| enum Error: Swift.Error { | |
| case permissionDenied | |
| case permissionRestricted | |
| case permissionNotDetermined | |
| } | |
| } | |
| protocol GeofenceBuildable { | |
| func ensurePermission() throws -> Geofence.PermissionMode | |
| func requestPermission( | |
| mode: Geofence.PermissionMode, | |
| completion: @escaping ((Geofence.PermissionMode?, Geofence.Error?) -> Void)) | |
| func build(geofence: Geofence) | |
| func destroy(geofenceIdentifier: String) | |
| func destroyAll() | |
| } | |
| class GeofenceHandler: NSObject { | |
| let manager = CLLocationManager() | |
| var enteringGeofence: ((String) -> Void)? | |
| var exitingGeofence: ((String?, Error?) -> Void)? | |
| override init() { | |
| super.init() | |
| manager.delegate = self | |
| } | |
| func ensurePermission() throws -> Geofence.PermissionMode { | |
| let authorizationStatus = CLLocationManager.authorizationStatus() | |
| switch authorizationStatus { | |
| case .denied: | |
| throw Geofence.Error.permissionDenied | |
| case .restricted: | |
| throw Geofence.Error.permissionRestricted | |
| case .notDetermined: | |
| throw Geofence.Error.permissionNotDetermined | |
| case .authorizedAlways: | |
| return .always | |
| case .authorizedWhenInUse: | |
| return .whenInAppUse | |
| } | |
| } | |
| private var requestPermissionHandler: ((Geofence.PermissionMode?, Geofence.Error?) -> Void)? | |
| func requestPermission( | |
| mode: Geofence.PermissionMode, | |
| completion: @escaping ((Geofence.PermissionMode?, Geofence.Error?) -> Void) = { _, _ in }) | |
| { | |
| requestPermissionHandler = { mode, error in | |
| completion(mode, error) | |
| } | |
| switch mode { | |
| case .always: | |
| manager.requestAlwaysAuthorization() | |
| case .whenInAppUse: | |
| manager.requestWhenInUseAuthorization() | |
| } | |
| } | |
| func addGeofence(geofence: Geofence) { | |
| let center = CLLocationCoordinate2DMake(geofence.latitude, geofence.longitude) | |
| let region = CLCircularRegion(center: center, radius: geofence.radius, identifier: geofence.identifier) | |
| manager.startMonitoring(for: region) | |
| } | |
| func removeGeofence(geofenceIdentifier: String) { | |
| guard let region = manager.monitoredRegions.first(where: { region in | |
| region.identifier == geofenceIdentifier | |
| }) else { | |
| return | |
| } | |
| manager.stopMonitoring(for: region) | |
| } | |
| func removeAllGeofence() { | |
| manager.monitoredRegions.forEach { [weak self] region in | |
| self?.manager.stopMonitoring(for: region) | |
| } | |
| } | |
| } | |
| extension GeofenceHandler: CLLocationManagerDelegate { | |
| func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { | |
| guard status != .notDetermined else { | |
| return | |
| } | |
| do { | |
| let mode = try ensurePermission() | |
| requestPermissionHandler?(mode, nil) | |
| } catch { | |
| precondition(error is Geofence.Error) | |
| requestPermissionHandler?(nil, error as? Geofence.Error) | |
| } | |
| } | |
| func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) { | |
| enteringGeofence?(region.identifier) | |
| } | |
| func locationManager(_ manager: CLLocationManager, monitoringDidFailFor region: CLRegion?, withError error: Error) { | |
| exitingGeofence?(region?.identifier, error) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment