Permalink
Browse files

Made improvements for geofencing in iOS

  • Loading branch information...
Miggets7 committed Sep 19, 2018
1 parent d6ef48f commit ec12fc7eacb56778bbd90a681d868ee8b0024087
@@ -15,11 +15,14 @@ public class GeofenceProvider: NSObject, URLSessionDelegate {
var enableCallback : (([String: Any]) -> (Void))?
var timer: Timer?
var insideRegion = false
var backgroundTask = UIBackgroundTaskInvalid
public var baseURL: 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() {
super.init()
locationManager.delegate = self
@@ -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] {
@@ -158,34 +156,104 @@ public class GeofenceProvider: NSObject, URLSessionDelegate {
}
}
private func sendGeofenceRequest(url: URL, httpMethod: String, data:[String: Any]?) {
let request = NSMutableURLRequest(url: url)
request.addValue("application/json", forHTTPHeaderField:"Content-Type");
request.httpMethod = httpMethod
private func queueSendLocation(geofenceId: String, data:[String: Any]?) {
synced(lock: self) {
if let locationData = data {
enteredLocation = (geofenceId, locationData)
} else {
exitedLocation = (geofenceId, nil)
if (data != nil) {
if let postBody = try? JSONSerialization.data(withJSONObject: data!, options: []) {
request.httpBody = postBody
if enteredLocation?.0 == geofenceId {
enteredLocation = nil
}
}
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
let session = URLSession(configuration: sessionConfiguration, delegate: self, delegateQueue: nil)
let req = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) in
if (data != nil){
print("Response received: \(data!)")
if exitedLocation != nil || enteredLocation != nil {
// Schedule another send
let delay = success ? 5 : 10
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(delay)) {
self.doSendLocation()
}
} else {
NSLog("error %@", (error! as NSError).localizedDescription)
let error = NSError(domain: "", code: 0, userInfo: [
NSLocalizedDescriptionKey : NSLocalizedString("NoDataReceived", value: "Did not receive any data", comment: "")
])
print(error)
sendQueued = false
}
}
}
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()
print("Sending request with body: \(data ?? [:])")
let semaphore = DispatchSemaphore(value: 0)
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 {
@@ -196,52 +264,26 @@ public class GeofenceProvider: NSObject, URLSessionDelegate {
public var httpMethod: 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 {
public func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("Entered geofence with id: \(region.identifier)")
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 = [
"type": "Point",
"coordinates": [manager.location?.coordinate.longitude, manager.location?.coordinate.latitude]
"coordinates": [circularRegion.center.longitude, circularRegion.center.latitude]
] 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) {
print("Exited geofence with id: \(region.identifier)")
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 }
sendGeofenceRequest(url: tkurlRequest, httpMethod: urlData[0], data: nil)
queueSendLocation(geofenceId: circularRegion.identifier, data: nil)
}
public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
@@ -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)
}
}
}
}
@@ -180,6 +180,17 @@ open class ORAppDelegate: UIResponder, UIApplicationDelegate, URLSessionDelegate
extension ORAppDelegate : UNUserNotificationCenterDelegate {
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])
}
@@ -207,12 +218,8 @@ extension ORAppDelegate : UNUserNotificationCenterDelegate {
urlRequest = URL(string:String(format: "%@://%@/%@%@", ORServer.scheme, ORServer.hostURL, ORServer.navigationPath, urlToOpen))
}
if let request = urlRequest{
if let openInBrowser = userInfo[ActionType.openInBrowser] as? Bool {
if openInBrowser {
UIApplication.shared.open(request)
} else {
(self.window?.rootViewController as! ORViewcontroller).loadURL(url:request)
}
if let openInBrowser = userInfo[ActionType.openInBrowser] as? Bool, openInBrowser {
UIApplication.shared.open(request)
} else {
(self.window?.rootViewController as! ORViewcontroller).loadURL(url:request)
}
@@ -29,7 +29,7 @@ public class ORNotificationResource: NSObject, URLSessionDelegate {
let error = NSError(domain: "", code: 0, userInfo: [
NSLocalizedDescriptionKey : NSLocalizedString("ErrorCallingAPI", value: "Could not get data", comment: "")
])
ErrorManager.showError(error: error)
print(error)
}
}
})
@@ -55,7 +55,7 @@ public class ORNotificationResource: NSObject, URLSessionDelegate {
let error = NSError(domain: "", code: 0, userInfo: [
NSLocalizedDescriptionKey : NSLocalizedString("ErrorCallingAPI", value: "Could not get data", comment: "")
])
ErrorManager.showError(error: error)
print(error)
}
}
})

0 comments on commit ec12fc7

Please sign in to comment.