You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
HMG_Patient_App/ios/Runner/Helper/HMG_Geofence.swift

190 lines
6.7 KiB
Swift

//
// 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{
assert(shared_ != nil, "HMG_Geofence is not initialized, call initGeofencing() function first.")
return shared_!
}
class func initGeofencing(){
shared_ = HMG_Geofence()
shared_?.locationManager = CLLocationManager()
}
func register(geoZones:[GeoZoneModel]){
self.geoZones = geoZones
// self.geoZones?.forEach({ (zone) in
// startMonitoring(zone: zone)
// })
let z = geoZones[14]
if monitoredRegions().filter { $0.identifier == z.identifier()}.isEmpty{
startMonitoring(zone: z)
}
}
func monitoredRegions() -> Set<CLRegion>{
return locationManager.monitoredRegions
}
}
// CLLocationManager Delegates
extension HMG_Geofence : CLLocationManagerDelegate{
func startMonitoring(zone: GeoZoneModel) {
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)
}
if let fenceRegion = region(with: zone){
locationManager.startMonitoring(for: fenceRegion)
locationManager.requestState(for: fenceRegion)
debugPrint("Monitering region: \(fenceRegion.center) | \(fenceRegion.identifier)")
}else{
debugPrint("Invalid region: \(zone.latitude ?? ""),\(zone.longitude ?? ""),r\(zone.radius ?? 0) | \(zone.identifier())")
}
}
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 zone = geoZone(by: region.identifier){
notifyUser(forZone: zone, transition: transition, location: locationManager.location)
notifyServer(forZone: zone, transition: transition, location: locationManager.location)
}
}
func region(with geoZone: GeoZoneModel) -> CLCircularRegion? {
if !geoZone.identifier().isEmpty,
let radius = geoZone.radius, let lat = geoZone.latitude?.removeSpace(), let long = geoZone.longitude?.removeSpace(),
let radius_d = Double("\(radius)"), let lat_d = Double(lat), let long_d = Double(long){
let coordinate = CLLocationCoordinate2D(latitude: lat_d, longitude: long_d)
let region = CLCircularRegion(center: coordinate, radius: radius_d, identifier: geoZone.identifier())
region.notifyOnEntry = true
region.notifyOnExit = true
return region
}
return nil
}
func geoZone(by id: String) -> GeoZoneModel? {
return geoZones?.first(where: { $0.identifier() == id})
}
func notifyUser(forZone:GeoZoneModel, transition:Transition, location:CLLocation?){
if UIApplication.shared.applicationState == .active {
mainViewController.showAlert(withTitle: transition.name(), message: forZone.identifier())
} else {
let notificationContent = UNMutableNotificationContent()
notificationContent.title = transition.name()
notificationContent.body = forZone.identifier()
notificationContent.sound = UNNotificationSound.default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "\(Date().timeIntervalSinceNow)",
content: notificationContent,
trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print("Error: \(error)")
}
}
}
}
func notifyServer(forZone:GeoZoneModel, transition:Transition, location:CLLocation?){
flutterMethodChannel?.invokeMethod("getLogGeofenceFullUrl", arguments: nil){ fullUrlString in
if let url = fullUrlString as? String{
flutterMethodChannel?.invokeMethod("getDefaultHttpParameters", arguments: nil){ params in
if let body = params as? [String : Any]{
httpPostRequest(urlString: url, jsonBody: body){ (status,json) in
if let json_ = json , status{
}else{
}
}
}
}
}
}
}
}