Skip to content

Commit

Permalink
Made improvements for geofencing in iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
Miggets7 committed Sep 19, 2018
1 parent d6ef48f commit ec12fc7
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 77 deletions.
168 changes: 99 additions & 69 deletions console/iOS/ORLib/ORLib/GeofenceProvider.swift
Expand Up @@ -15,11 +15,14 @@ public class GeofenceProvider: NSObject, URLSessionDelegate {
var enableCallback : (([String: Any]) -> (Void))? var enableCallback : (([String: Any]) -> (Void))?
var timer: Timer? var timer: Timer?
var insideRegion = false var insideRegion = false
var backgroundTask = UIBackgroundTaskInvalid


public var baseURL: String = "" public var baseURL: String = ""
public var consoleId: String = "" public var consoleId: String = ""


private var enteredLocation: (String, [String : Any]?)? = nil
private var exitedLocation: (String, [String : Any]?)? = nil
private var sendQueued = false

public override init() { public override init() {
super.init() super.init()
locationManager.delegate = self locationManager.delegate = self
Expand Down Expand Up @@ -106,11 +109,6 @@ public class GeofenceProvider: NSObject, URLSessionDelegate {
]) ])
} }
} }
resetTimer()
NotificationCenter.default.addObserver(forName: NSNotification.Name.UIApplicationDidEnterBackground, object: nil, queue:nil, using: { notification in
self.backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in self?.endBackgroundTask()}
self.resetTimer()
})
} }


public func disbale()-> [String: Any] { public func disbale()-> [String: Any] {
Expand Down Expand Up @@ -158,34 +156,104 @@ public class GeofenceProvider: NSObject, URLSessionDelegate {
} }
} }


private func sendGeofenceRequest(url: URL, httpMethod: String, data:[String: Any]?) { private func queueSendLocation(geofenceId: String, data:[String: Any]?) {
let request = NSMutableURLRequest(url: url) synced(lock: self) {
request.addValue("application/json", forHTTPHeaderField:"Content-Type"); if let locationData = data {
request.httpMethod = httpMethod enteredLocation = (geofenceId, locationData)
} else {
exitedLocation = (geofenceId, nil)


if (data != nil) { if enteredLocation?.0 == geofenceId {
if let postBody = try? JSONSerialization.data(withJSONObject: data!, options: []) { enteredLocation = nil
request.httpBody = postBody }
}

if !sendQueued {
sendQueued = true
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) {
self.doSendLocation()
}
} }
} else {
request.httpBody = "null".data(using: .utf8)
} }
}

private func doSendLocation() {
synced(lock: self) {
var success = false

if exitedLocation != nil {
if sendLocation(geofenceId: exitedLocation!.0, data: exitedLocation!.1) {
exitedLocation = nil
success = true
}
} else if enteredLocation != nil {
if sendLocation(geofenceId: enteredLocation!.0, data: enteredLocation!.1) {
enteredLocation = nil
success = true
}
}


let sessionConfiguration = URLSessionConfiguration.default if exitedLocation != nil || enteredLocation != nil {
let session = URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: nil) // Schedule another send
let req = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) in let delay = success ? 5 : 10
if (data != nil){ DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(delay)) {
print("Response received: \(data!)") self.doSendLocation()
}
} else { } else {
NSLog("error %@", (error! as NSError).localizedDescription) sendQueued = false
let error = NSError(domain: "", code: 0, userInfo: [ }
NSLocalizedDescriptionKey : NSLocalizedString("NoDataReceived", value: "Did not receive any data", comment: "") }
]) }
print(error)
private func sendLocation(geofenceId: String, data: [String : Any]?)-> Bool {
return synced(lock: self) {
var succes = false

guard let urlData = geoPostUrls[geofenceId] else {
return succes
}
guard let url = URL(string: "\(baseURL)\(urlData[1])") else { return succes}

let request = NSMutableURLRequest(url: url)
request.addValue("application/json", forHTTPHeaderField:"Content-Type");
request.httpMethod = urlData[0]

if (data != nil) {
if let postBody = try? JSONSerialization.data(withJSONObject: data!, options: []) {
request.httpBody = postBody
}
} else {
request.httpBody = "null".data(using: .utf8)
} }
})
req.resume() let semaphore = DispatchSemaphore(value: 0)
print("Sending request with body: \(data ?? [:])") let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: nil)
let req = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) in
if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 204 {
print("sendLocation succeded")
succes = true
} else {
print("sendLocation failed")
if error != nil {
print(error!)
}
}
semaphore.signal()
})
req.resume()
semaphore.wait()
return succes
}
}

private func synced<T>(lock: Any, closure: () throws -> T) rethrows -> T {
objc_sync_enter(lock)
defer {
objc_sync_exit(lock)
}

return try closure()
} }


public class GeofenceDefinition: NSObject, Decodable { public class GeofenceDefinition: NSObject, Decodable {
Expand All @@ -196,52 +264,26 @@ public class GeofenceProvider: NSObject, URLSessionDelegate {
public var httpMethod: String = "" public var httpMethod: String = ""
public var url: String = "" public var url: String = ""
} }

func endBackgroundTask() {
UIApplication.shared.endBackgroundTask(self.backgroundTask)
self.backgroundTask = UIBackgroundTaskInvalid
resetTimer()
}

func resetTimer() {
self.timer?.invalidate()
self.timer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true, block: { timer in
self.insideRegion = false
for region in self.locationManager.monitoredRegions {
self.locationManager.requestState(for: region)
}
})
}
} }


extension GeofenceProvider: CLLocationManagerDelegate { extension GeofenceProvider: CLLocationManagerDelegate {
public func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) { public func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("Entered geofence with id: \(region.identifier)") print("Entered geofence with id: \(region.identifier)")
guard let circularRegion = region as? CLCircularRegion else {return} guard let circularRegion = region as? CLCircularRegion else {return}


guard let urlData = geoPostUrls[circularRegion.identifier] else {
return
}
guard let tkurlRequest = URL(string: "\(baseURL)\(urlData[1])") else { return }

let postData = [ let postData = [
"type": "Point", "type": "Point",
"coordinates": [manager.location?.coordinate.longitude, manager.location?.coordinate.latitude] "coordinates": [circularRegion.center.longitude, circularRegion.center.latitude]
] as [String : Any] ] as [String : Any]


sendGeofenceRequest(url: tkurlRequest, httpMethod: urlData[0], data: postData) queueSendLocation(geofenceId: circularRegion.identifier, data: postData)
} }


public func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) { public func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("Exited geofence with id: \(region.identifier)") print("Exited geofence with id: \(region.identifier)")
guard let circularRegion = region as? CLCircularRegion else {return} guard let circularRegion = region as? CLCircularRegion else {return}


guard let urlData = geoPostUrls[circularRegion.identifier] else { queueSendLocation(geofenceId: circularRegion.identifier, data: nil)
return
}
guard let tkurlRequest = URL(string: "\(baseURL)\(urlData[1])") else { return }

sendGeofenceRequest(url: tkurlRequest, httpMethod: urlData[0], data: nil)
} }


public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
Expand All @@ -254,16 +296,4 @@ extension GeofenceProvider: CLLocationManagerDelegate {
]) ])
} }
} }

public func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
switch state {
case .inside:
insideRegion = true
manager.delegate?.locationManager?(manager, didEnterRegion: region)
default:
if !insideRegion {
manager.delegate?.locationManager?(manager, didExitRegion: region)
}
}
}
} }
19 changes: 13 additions & 6 deletions console/iOS/ORLib/ORLib/ORAppDelegate.swift
Expand Up @@ -180,6 +180,17 @@ open class ORAppDelegate: UIResponder, UIApplicationDelegate, URLSessionDelegate
extension ORAppDelegate : UNUserNotificationCenterDelegate { extension ORAppDelegate : UNUserNotificationCenterDelegate {


open func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { open func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
let userInfo = notification.request.content.userInfo
var notificationId : Int64? = nil
let consoleId = UserDefaults.standard.string(forKey: GeofenceProvider.consoleIdKey)

if let notificationIdString = userInfo[ActionType.notificationId] as? String{
notificationId = Int64(notificationIdString)
}
if let notiId = notificationId, let conId = consoleId {
ORNotificationResource.sharedInstance.notificationDelivered(notificationId: notiId, targetId: conId)
}

completionHandler([.alert, .sound]) completionHandler([.alert, .sound])
} }


Expand Down Expand Up @@ -207,12 +218,8 @@ extension ORAppDelegate : UNUserNotificationCenterDelegate {
urlRequest = URL(string:String(format: "%@://%@/%@%@", ORServer.scheme, ORServer.hostURL, ORServer.navigationPath, urlToOpen)) urlRequest = URL(string:String(format: "%@://%@/%@%@", ORServer.scheme, ORServer.hostURL, ORServer.navigationPath, urlToOpen))
} }
if let request = urlRequest{ if let request = urlRequest{
if let openInBrowser = userInfo[ActionType.openInBrowser] as? Bool { if let openInBrowser = userInfo[ActionType.openInBrowser] as? Bool, openInBrowser {
if openInBrowser { UIApplication.shared.open(request)
UIApplication.shared.open(request)
} else {
(self.window?.rootViewController as! ORViewcontroller).loadURL(url:request)
}
} else { } else {
(self.window?.rootViewController as! ORViewcontroller).loadURL(url:request) (self.window?.rootViewController as! ORViewcontroller).loadURL(url:request)
} }
Expand Down
4 changes: 2 additions & 2 deletions console/iOS/ORLib/ORLib/ORNotificationResource.swift
Expand Up @@ -29,7 +29,7 @@ public class ORNotificationResource: NSObject, URLSessionDelegate {
let error = NSError(domain: "", code: 0, userInfo: [ let error = NSError(domain: "", code: 0, userInfo: [
NSLocalizedDescriptionKey : NSLocalizedString("ErrorCallingAPI", value: "Could not get data", comment: "") NSLocalizedDescriptionKey : NSLocalizedString("ErrorCallingAPI", value: "Could not get data", comment: "")
]) ])
ErrorManager.showError(error: error) print(error)
} }
} }
}) })
Expand All @@ -55,7 +55,7 @@ public class ORNotificationResource: NSObject, URLSessionDelegate {
let error = NSError(domain: "", code: 0, userInfo: [ let error = NSError(domain: "", code: 0, userInfo: [
NSLocalizedDescriptionKey : NSLocalizedString("ErrorCallingAPI", value: "Could not get data", comment: "") NSLocalizedDescriptionKey : NSLocalizedString("ErrorCallingAPI", value: "Could not get data", comment: "")
]) ])
ErrorManager.showError(error: error) print(error)
} }
} }
}) })
Expand Down

0 comments on commit ec12fc7

Please sign in to comment.