// // HMG_Geofence.swift // Runner // // Created by ZiKambrani on 13/12/2020. // import UIKit import CoreLocation fileprivate var df = DateFormatter() fileprivate var transition = "" enum Transition:Int { case entry = 1 case exit = 2 func name() -> String{ return self.rawValue == 1 ? "Enter" : "Exit" } } class HMG_Geofence:NSObject{ var geoZones:[GeoZoneModel]? var locationManager:CLLocationManager!{ didSet{ // https://developer.apple.com/documentation/corelocation/cllocationmanager/1423531-startmonitoringsignificantlocati locationManager.allowsBackgroundLocationUpdates = true locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters locationManager.activityType = .other locationManager.delegate = self locationManager.requestAlwaysAuthorization() // locationManager.distanceFilter = 500 // locationManager.startMonitoringSignificantLocationChanges() } } private static var shared_:HMG_Geofence? class func shared() -> HMG_Geofence{ if HMG_Geofence.shared_ == nil{ HMG_Geofence.initGeofencing() } return shared_! } class func initGeofencing(){ shared_ = HMG_Geofence() shared_?.locationManager = CLLocationManager() } func register(geoZones:[GeoZoneModel]){ self.geoZones = geoZones let monitoredRegions_ = monitoredRegions() self.geoZones?.forEach({ (zone) in if let region = zone.toRegion(locationManager: locationManager){ if let already = monitoredRegions_.first(where: {$0.identifier == zone.identifier()}){ debugPrint("Already monitering region: \(already)") }else{ startMonitoring(region: region) } }else{ debugPrint("Invalid region: \(zone.latitude ?? "invalid_latitude"),\(zone.longitude ?? "invalid_longitude"),r\(zone.radius ?? 0) | \(zone.identifier())") } }) } func monitoredRegions() -> Set{ return locationManager.monitoredRegions } func unRegisterAll(){ for region in locationManager.monitoredRegions { locationManager.stopMonitoring(for: region) } } } // CLLocationManager Delegates extension HMG_Geofence : CLLocationManagerDelegate{ func startMonitoring(region: CLCircularRegion) { if !CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) { return } if CLLocationManager.authorizationStatus() != .authorizedAlways { let message = """ Your geotification is saved but will only be activated once you grant HMG permission to access the device location. """ debugPrint(message) } locationManager.startMonitoring(for: region) locationManager.requestState(for: region) debugPrint("Starts monitering region: \(region)") } func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) { debugPrint("didEnterRegion: \(region)") if region is CLCircularRegion { handleEvent(for: region,transition: .entry, location: manager.location) } } func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) { debugPrint("didExitRegion: \(region)") if region is CLCircularRegion { handleEvent(for: region,transition: .exit, location: manager.location) } } func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) { debugPrint("didDetermineState: \(state)") } func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { debugPrint("didUpdateLocations: \(locations)") } } // Helpers extension HMG_Geofence{ func handleEvent(for region: CLRegion!, transition:Transition, location:CLLocation?) { if let userProfile = userProfile(){ notifyUser(forRegion: region, transition: transition, location: locationManager.location, userProfile: userProfile) notifyServer(forRegion: region, transition: transition, location: locationManager.location, userProfile: userProfile) } } func geoZone(by id: String) -> GeoZoneModel? { var zone:GeoZoneModel? = nil if let zones_ = geoZones{ zone = zones_.first(where: { $0.identifier() == id}) }else{ // let jsonArray = UserDefaults.standard.string(forKey: "hmg-geo-fences") } return zone } func notifyUser(forRegion:CLRegion, transition:Transition, location:CLLocation?, userProfile:[String:Any?]){ if let patientId = userProfile["PatientID"] as? Int{ } } func notifyServer(forRegion:CLRegion, transition:Transition, location:CLLocation?, userProfile:[String:Any?]){ if let patientId = userProfile["PatientID"] as? Int{ if let idString = forRegion.identifier.split(separator: "_").first, let idInt = Int(idString){ let body:[String:Any] = [ "PointsID":idInt, "GeoType":transition.rawValue, "PatientID":patientId ] var logs = UserDefaults.init(suiteName: "GeoFenceLog")?.dictionary(forKey: "GEOFENCE_LOGS") ?? [:] var geo = (logs[forRegion.identifier] as? [String]) ?? [] let url = "https://hmgwebservices.com/Services/Patients.svc/REST/GeoF_InsertPatientFileInfo" httpPostRequest(urlString: url, jsonBody: body){ (status,json) in let status_ = status ? "Notified successfully:" : "Failed to notify:" showNotification(title: transition.name(), subtitle: forRegion.identifier, message: status_) geo.append("\(status_) \(transition.name()) at \(Date().toString(format: "dd/MMM/yyy hh:mm:ss"))") logs.updateValue( geo, forKey: forRegion.identifier) UserDefaults.init(suiteName: "GeoFenceLog")?.set(logs, forKey: "GEOFENCE_LOGS") } } } } }