How to check if user's current location is inside a location circle - ios

i want to check if user if inside a vicinity. For example i have specified a radius of 50 meters around current of location of user. Let's say if user is moving, now i want to check if user in inside 50 meter radius or not. Here is my code
override func viewDidLoad() {
super.viewDidLoad()
locationManager.startMonitoringVisits()
locationManager.delegate = self
locationManager.distanceFilter = 1
locationManager.allowsBackgroundLocationUpdates = true
locationManager.startUpdatingLocation()
}
Here is code for checking distance
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.first else {
return
}
let officeLocation = CLLocationCoordinate2D.init(latitude: 31.471303736482234, longitude: 74.27275174139386)
let circle = MKCircle(center: officeLocation, radius: 50 as CLLocationDistance)
if location.distance(from: officeLocation) > circle.radius {
self.newVisitReceived(des: "YOU ARE OUT OF OFFICE")
}
else{
self.newVisitReceived(des: "YOU ARE IN OFFICE")
}
}
Even if i don't move this code sends notification "YOU ARE OUT".

I would solve this with Geofences...
You have to specify a coordinate center & radius where you want to listen to the user when he goes inside/outside from your geofence.
override func viewDidLoad() {
super.viewDidLoad()
let locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
locationManager.allowsBackgroundLocationUpdates = true
locationManager.requestAlwaysAuthorization()
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways || status == .authorizedWhenInUse {
// CLLocationCoordinate2D; You have to put the coordinate that you want to listen
let region = CLCircularRegion(center: CLLocationCoordinate2D(latitude: 324234, longitude: 23423), radius: 50, identifier: "Ur ID")
region.notifyOnExit = true
region.notifyOnEntry = true
manager.startMonitoring(for: region)
}
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
// User has exited from ur regiom
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
// User has exited from ur region
}
I hope this will be useful

The general problem with location services is that the measurements vary in accuracy, depending on a lot of factors. How would your like your code to behave if the user is standing right on the 50 meter boundary? Your current code would then flip back and forth randomly between 'in office' and 'out of office', if the accuracy is bad.
I think accuracy of a GPS is actually more than 4 meters under the best conditions, so a distanceFilter of 1 might not be appropriate.
I guess you would need some state in your app that tracks when the user was last seen inside the 50 meter radius, and also some grace period before updating that variable again, to avoid 'flickering'.

Related

How to get accurate current location coordinates (latitude/longititude) in IOS Swift

I am using CoreLocation in IOS Swift to get the current coordinates but for some cases, it gives me closest to my desired location while sometimes the coordinates are many meters away from my given address. please check my code which I am using is there any other way to get an accurate current location coordinates.?
My Code is :
import CoreLocation
var locationManager:CLLocationManager!
var userLat = 0.0
var userLong = 0.0
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager = CLLocationManager()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled(){
self.locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations:
[CLLocation]) {
guard let userLocation :CLLocation = locations.first else{return}
userLat = userLocation.coordinate.latitude
userLong = userLocation.coordinate.longitude
//current location
print("current location latitude is :%#", userLat)
print("current location longitude is :%#", userLong)
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(Error: \(error)")
}
Please help me some time current location is accurate and sometimes it's too meters away. Thanks
Assuming the user of your app has allowed you use precise locations you still need to take into account the fact that the location provided is only as accurate as the hardware can provide. It takes time for the location to get accurate and you may see several calls to didUpdateLocations as the system warms up.
You can use horizontalAccuracy and verticalAccuracy on a CLLocation to make decisions on what to do with a position update.

Is that possible to receive Location even when app is not running in Swift

I am making an app that trace all the trips made by a user.
The app works perfectly when it is in background or in foreground but I am looking for a way to get it worked even if the app is not running.
I followed exactly this answer : Receiving Location even when app is not running in Swift
But this doesn't work as expected.
I have two property in my AppDelegate
var lastLocation:CLLocation?
//And a location manager
var locationManager = CLLocationManager()
In my DidFinishLaunchingWithOptions I configure the CLLocationManager
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
In my applicationWillTerminate :
lastLocation = HomeController.locations.last
createRegion(location: lastLocation)
Here is the rest :
func createRegion(location:CLLocation?) {
if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
let coordinate = CLLocationCoordinate2DMake((location?.coordinate.latitude)!, (location?.coordinate.longitude)!)
let regionRadius = 50.0
let region = CLCircularRegion(center: CLLocationCoordinate2D(
latitude: coordinate.latitude,
longitude: coordinate.longitude),
radius: regionRadius,
identifier: "aabb")
region.notifyOnExit = true
region.notifyOnEntry = true
//Send your fetched location to server
UserDefaults.standard.set(UserDefaults.standard.integer(forKey: "nbLocNotrunning") + 1, forKey: "nbLocNotrunning")
//Stop your location manager for updating location and start regionMonitoring
self.locationManager.stopUpdatingLocation()
self.locationManager.startMonitoring(for: region)
} else {
print("System can't track regions")
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print("Entered Region")
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
print("Exited Region")
locationManager.stopMonitoring(for: region)
//Start location manager and fetch current location
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if UIApplication.shared.applicationState != .inactive {
} else {
//App is in BG/ Killed or suspended state
//send location to server
// create a New Region with current fetched location
let location = locations.last
lastLocation = location
//Make region and again the same cycle continues.
self.createRegion(location: lastLocation)
}
}
I wonder where the mistake can come from and why I never enter in the function didExitRegion.
For now, I just increment a variable in UserDefaut "nbLocNotrunning" in order to know how many times I leave a region but this number never increase when I stop my app.

startMonitoringSignificantLocationChange does not invoke didUpdateLocations

I trying to record a path user is taking using GoogleMap SDK. I'm using polyline to draw line on a map to show user the path that is taken. In an attempt to cut down coordinates that is generated and to make line looks clean(instead of looking squiggly), I'm calling startMonitoringSignificantChange of CLLocationManger instead of startUpdatingLocation. However, that does not seem to work. It calls didUpdateLocations method just once when the view is loaded, but after that, it just stops calling. Where am I doing wrong?
This is my code
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.requestAlwaysAuthorization()
locationManager.startMonitoringSignificantLocationChanges()
}
extension LocationViewController: CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .AuthorizedAlways {
locationManager.startMonitoringSignificantLocationChanges()
mapView.myLocationEnabled = true
mapView.settings.myLocationButton = true
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = manager.location {
path.addCoordinate(CLLocationCoordinate2D(latitude: location.coordinate.latitude,
longitude: location.coordinate.longitude))
let polyline = GMSPolyline(path: path)
polyline.strokeColor = UIColor.redColor()
polyline.strokeWidth = 3
polyline.geodesic = true
polyline.map = mapView
// Save the coordinates to array
coordinateArray.append([location.coordinate.latitude, location.coordinate.longitude])
}
}
}
}
Add following lines of codes after locationManager.requestAlwaysAuthorization()
locationManager.allowsBackgroundLocationUpdates = true
locationManager.pausesLocationUpdatesAutomatically = false
p.s. If your view is holding locationManager instance, it may not receive location-updates after your view is un-loaded. You may remove following line as it is useless for significant-location-updates:
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters

didEnterRegion, didExitRegion not being called

I've been experimenting with region monitoring in order to show an alert or a local notification when the user is within the set region. As a first step, I added a print line to see if it works on the debug area. However, while the other lines are being printed, I'm not getting anything for didEnterRegion and didExitRegion.
I am simulating the location to be in/outside of the given region but I am having no luck. It will be great if someone could look at the code below and see what I've missed. Thank you.
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var manager = CLLocationManager?()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
manager = CLLocationManager()
let latitude: CLLocationDegrees = 48.858400
let longitude: CLLocationDegrees = 2.294500
let center: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let radius: CLLocationDistance = CLLocationDistance(100.0)
let identifier: String = "Notre Dame"
let currRegion = CLCircularRegion(center: center, radius: radius, identifier: identifier)
manager?.distanceFilter = 10
manager?.desiredAccuracy = kCLLocationAccuracyBest
currRegion.notifyOnEntry = true
currRegion.notifyOnExit = true
manager?.requestWhenInUseAuthorization()
manager?.delegate = self
manager?.pausesLocationUpdatesAutomatically = true
manager?.startMonitoringForRegion(currRegion)
manager?.startUpdatingLocation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(manager: CLLocationManager, didStartMonitoringForRegion region: CLRegion) {
print("The monitored regions are: \(manager.monitoredRegions)")
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
print("locations = \(locValue.latitude) \(locValue.longitude)")
}
func locationManager(manager: CLLocationManager, didEnterRegion region: CLRegion) {
NSLog("Entered")
}
func locationManager(manager: CLLocationManager, didExitRegion region: CLRegion) {
NSLog("Exited")
}
}
You can make it work by changing
manager?.requestWhenInUseAuthorization()
to
manager?.requestAlwaysAuthorization()
then add to your info.plist file this key
NSLocationAlwaysUsageDescription with value "This is for testing purpose" or whatever text you want this is what will appear to user requesting to use location

How to make location more accurate in iOS?

I am building a location based app. Is there anyway to make the location I am getting through CLLocationManager more accurate?
I need to make sure the accuracy is within 50 meters.
Here is my code so far:
func startSignificantChangeUpdates(){
if (locationManager.respondsToSelector(Selector("requestWhenInUseAuthorization"))) {
locationManager.requestWhenInUseAuthorization()
}else {
locationManager.startUpdatingLocation()
}
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
location = locationManager.location
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
if let newLocation = locations.last as? CLLocation {
//Lets not bother if the location is less than 500 meters
let oldLocation = location
location = newLocation
var distance = oldLocation?.distanceFromLocation(newLocation)
if distance > 500 {
NSNotificationCenter.defaultCenter().postNotificationName("location", object: self)
}
if distance > 50 {
NSNotificationCenter.defaultCenter().postNotificationName("imatlocation", object: self)
}
}
}
For accuracy of the returned location you need to check the horizontalAccuracy of the location, that will give you the radius of uncertainty for the location (in meters) you can then decide to act on or reject the location based on how accurate it is.
You can change your desired accuracy to use
kCLLocationAccuracyBest

Resources