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.
190 lines
6.7 KiB
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{
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|