Swift GeoPoint get ALL users location ios - ios

I am trying to make a app where everyone can see everyones location at the same map. I can't find any tutorials on how to retrieve ALL users location on the same map.
I have manage to make a script which uploads the users location into Parse with this script:
PFGeoPoint.geoPointForCurrentLocationInBackground {
(geoPoint: PFGeoPoint?, Error : NSError?) -> Void in
if let geoPoint = geoPoint{
PFUser.currentUser()? ["location"] = geoPoint
PFUser.currentUser()?.saveInBackground()
I have also manage to get the location of the current user.
Any one know how i can display everyones location, not just mine?
Thank you for your time and help. I am very new to Swift so let me know if i need to provide more information.
Here is my display code.
PFGeoPoint.geoPointForCurrentLocationInBackground {
(geoPoint: PFGeoPoint?, Error : NSError?) -> Void in
if let geoPoint = geoPoint{
PFUser.currentUser()? ["location"] = geoPoint
PFUser.currentUser()?.saveInBackground()
self.MapView?.showsUserLocation = true
self.MapView?.delegate = self
MapViewLocationManager.delegate = self
MapViewLocationManager.startUpdatingLocation()
self.MapView?.setUserTrackingMode(MKUserTrackingMode.Follow, animated: false)
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled(){
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocationManager]){
var locValue:CLLocationCoordinate2D = (manager.location?.coordinate)!
print("locations = \(locValue.latitude) \(locValue.longitude)")
Outside ViewWDidLoad
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
self.MapView?.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
}

To get all users location is not so simple as you think. The most time regular app is working in the background. In the background app can be in background or suspended or terminated state ( about states). And you have to get location from any of these states. How is it possible: you should enable Background Mode for location tracking for your app. To do it simpler - use significant location tracking for all users, but accuracy will be about 500m. To get more accuracy (but more difficult implementation) you can send silent push notification to users (about silent push), it wakes up app from terminated or suspended states to background state, and now you can get and send users current location to your server.

Related

How to track user location in the background swift

I am trying to track the user location in background I have try using when In us with and without always , but every time I minimise the app the location icon disappear I have read in a tutorial it should show blue bar but I am not getting that bar I have also check the background mode for updating the location
map.showsUserLocation = true
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
// Do any additional setup after loading the view, typically from a nib.
alwaysAuthorization()
}
func alwaysAuthorization(){
if CLLocationManager.locationServicesEnabled() && CLLocationManager.authorizationStatus() == .authorizedWhenInUse {
locationManager.requestAlwaysAuthorization()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let region = MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude), span: MKCoordinateSpan (latitudeDelta: 0.2, longitudeDelta: 0.2))
self.map.region = region
print("location \(location!.coordinate.latitude) and \(location!.coordinate.longitude)")
}
this what I was looking for
locationManager.allowsBackgroundLocationUpdates = true
You can use startMonitoringSignificantLocationChanges() method instead of startUpdatingLocation()
Based on docs:
Apps can expect a notification as soon as the device moves 500 meters or more from its previous notification. It should not expect notifications more frequently than once every five minutes. If the device is able to retrieve data from the network, the location manager is much more likely to deliver notifications in a timely manner.
I have used this method once and tested it. It works well with cellular and wi-fi.
Your question is not clear. Do you have problems running your app in background? Or do you simple expect the blue bar indicating that your app tracks the location in background?
For the latter you need to enable the background location indicator
locationManager.showsBackgroundLocationIndicator = true

How to get exact current location for google maps with accuracy less than 1 meter, Swift 4?

I am working on construction project and for that I want to fetch exact current location which must satisfy the accuracy withing the 1 meter. I am using google maps with SDK "CLLocationManager" and I am getting the current location but the location is not exact, it has some (+/-)5 meters to (+/-)10 meters error in location. I want the exact/accurate current location which should not exceeds the location accuracy error more than a feet.
Please help me out to fetch EXACT CURRENT LOCATION.
Also, is there any third party library, any hardware device (which I can connect to iOS device.) or anything else, please let me know.
Your valuable comment will be most appreciate.
Edited:-
Here I am sharing my code to get the current location using CLLocationManager:
override func viewDidLoad()
{
super.viewDidLoad()
self.locationManager = CLLocationManager()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let position = CLLocationCoordinate2D(latitude: manager.location!.coordinate.latitude, longitude: manager.location!.coordinate.longitude)
marker.position = position
print("position:",position)
}
Thank you..
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
guard let location = manager.location else{
return
}
var currentLocationCoordinate = location.coordinate
}
using this delegate function you will get the current location
You can use external gps if you want to get the exact location, with the help of device you will always get this fluctuation. You can also set your location accuracy to best.
https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/LocationBestPractices.html
You should always relay on GPS for accurate location. You can set locationManager.desireAccuracy = kCLLocationAccuracyBest. It will call you locationManager didUpdateLocation with the location array with each location having its accuracy you can apply your logic here.
Be alert to call locationManager.stopUpdatingLocation() when you done with desire accuracy location.
e.g
let horizontalAccuracy: Double = 20.0
let howRecent = location.timestamp.timeIntervalSinceNow
guard CLLocationCoordinate2DIsValid(location.coordinate),
location.horizontalAccuracy > 0,
location.horizontalAccuracy < horizontalAccuracy,
abs(howRecent) < 10 else { return false }
return true
}

CLLocationManager geofencing not working

I am trying to get geofencing working in CoreLocation but even though I am standing right on top of the lat/long point, didEnterRegion never gets called.
Here's my code:
override func viewDidAppear(_ animated: Bool) {
myLocationManager = CLLocationManager()
myLocationManager.delegate = self
myLocationManager.desiredAccuracy = kCLLocationAccuracyBest
if CLLocationManager.authorizationStatus() == .notDetermined {
myLocationManager.requestAlwaysAuthorization()
} else if CLLocationManager.authorizationStatus() == .authorizedAlways {
let geoSet = arrLocSets[2]
let regionLocation: CLLocation = CLLocation(latitude: geoSet[0], longitude: geoSet[1])
let region = CLCircularRegion(center: regionLocation.coordinate, radius: 30, identifier: "region1")
region.notifyOnEntry = true
region.notifyOnExit = false
myLocationManager.startMonitoring(for: region)
print(myLocationManager.monitoredRegions)
}
if CLLocationManager.locationServicesEnabled() {
myLocationManager.startUpdatingLocation()
}
}
the print call logs this:
CLCircularRegion (identifier:'region1', center:<+40.20675900,-75.48613300>, radius:30.00m)]
which is correct.
the print call in
func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
print("started monitoring!")
}
prints to the log so I know at least the monitoring started.
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
print(region)
/*
if let region = region as? CLCircularRegion {
let myAlert = UIAlertController(title: "Entered Region", message: "You found the region \(region.identifier)", preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
myAlert.addAction(okAction)
present(myAlert, animated: true, completion: nil)
}
*/
}
and here's a screen capture from my phone, where I was tracking lat/long. (Ignore the bottom labels, those are previous hard coded coordinates).
I put a break point in didEnterRegion and it never get triggered. 206851 and 206759 should be within a 30M diameter of each other? No? Did I miss a set up step?
didEnterRegion/didExitRegion happens on status change only. When starting to monitor for a region while being inside of the region you will not receive didEnterRegion.
Start walking out until didExitRegion happens, and this will "rearm" the region for didEnterRegion events, now you can walk back in.
Just do not be surprised that you will have to walk much more than 30m in each direction to trigger the events. Be prepared for up to 300 meters journey - really depends on your speed and (wireless) environment. Region monitoring does not involve GPS at all, it is all about wifi/cell tower triangulation - depends on coverage, quality of prior measurements and it is not "real time", as it is driven by wifi/cell scans.

iOS Region Monitoring not working

I have been doing some iOS development for a couple of months and recently I am developing a bus app.
I am currently mimicking the bus' movements and set up multiple annotations on the bus stops. For test purposes, I have setup just one bus stop and am trying to monitor when the bus has entered this region and exited as well.
Strangely, my didStartMonitoringForRegion method is called perfectly but neither the didEnterRegion nor didExitRegion methods are called. Every time I run the program, the bus pretty much passes the stop without prompting me so.
Could someone explain to me why this is happening and how to resolve it?
let locationManager = CLLocationManager()
var allBusAnnotations = [MKPointAnnotation]()
var summitEastBusStations = [CLLocationCoordinate2D]()
var busStopNames = ["Dix Stadium", "Risman Plaza", "Terrace Drive", "Terrace Drive 2","C-Midway","Theatre Dr.","East Main Street","South Lincoln"]
var radius = 500 as CLLocationDistance
// 0.02 is the best zoom in factor
var mapZoomInFactor : Double = 0.02
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.getBusStop()
self.locationManager.delegate = self
// gets the exact location of the user
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
// gets the user's location only when the app is in use and not background
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
self.setBusStopAnnotations(summitEastBusStations)
// self.mapView.mapType = MKMapType.Satellite
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
// sends the latitude and longitude to the Apple Servers then returns the address
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: { (placeMarks: [AnyObject]!, error: NSError!) -> Void in
if error != nil
{
println("Reverse Geocode Failed: " + error.localizedDescription)
return
}
if placeMarks.count > 0
{
// gets the most updated location
let pm = placeMarks.last as! CLPlacemark
let centre = CLLocationCoordinate2D(latitude: manager.location.coordinate.latitude, longitude: manager.location.coordinate.longitude)
// draws a circle in which the map will zoom to
let region = MKCoordinateRegion(center: centre, span: MKCoordinateSpan(latitudeDelta: self.mapZoomInFactor, longitudeDelta: self.mapZoomInFactor))
self.mapView.setRegion(region, animated: true)
self.displayLocationInfo(pm)
// self.distanceToClosestAnnotation(pm)
self.geoFencing()
// YOU CAN IGNORE THIS WHOLE PART. IT'S IRRELEVANT FOR THIS QUESTION
var repeatTimes = 0
var count = 0
while(count <= 7)
{
if count == (self.summitEastBusStations.count - 1)
{
count = 1
++repeatTimes
}
else if repeatTimes == 1
{
count = 0
++repeatTimes
}
else if repeatTimes == 2
{
break
}
self.distanceToBusStop(pm, count: count)
++count
}
}
})
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println("Location Manager Failed: " + error.localizedDescription)
}
func locationManager(manager: CLLocationManager!, didStartMonitoringForRegion region: CLRegion!) {
println("The region is monitored")
println("The monitored region is \(region.description)")
}
func locationManager(manager: CLLocationManager!, monitoringDidFailForRegion region: CLRegion!, withError error: NSError!) {
println("Failed to monitor the stated region")
}
func locationManager(manager: CLLocationManager!, didEnterRegion region: CLRegion!) {
println("The bus has entered the region")
}
func locationManager(manager: CLLocationManager!, didExitRegion region: CLRegion!) {
println("The bus has left the region")
}
func geoFencing()
{
let rismanPlaza = CLLocationCoordinate2D(latitude: 41.1469492, longitude: -81.344068)
var currentBusStop = CLLocation(latitude: rismanPlaza.latitude, longitude: rismanPlaza.longitude)
addRadiusCircle(currentBusStop)
let busStopRegion = CLCircularRegion(center: CLLocationCoordinate2D(latitude: rismanPlaza.latitude, longitude: rismanPlaza.longitude), radius: radius, identifier: busStopNames[1])
if radius > self.locationManager.maximumRegionMonitoringDistance
{
radius = self.locationManager.maximumRegionMonitoringDistance
}
locationManager.startMonitoringForRegion(busStopRegion)
}
// creates the radius around the specified location
func addRadiusCircle(location: CLLocation)
{
self.mapView.delegate = self
var circle = MKCircle(centerCoordinate: location.coordinate, radius: radius)
self.mapView.addOverlay(circle)
}
// performs the actual circle colouring
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer!
{
if overlay is MKCircle
{
var circle = MKCircleRenderer(overlay: overlay)
circle.strokeColor = UIColor.redColor()
circle.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.1)
circle.lineWidth = 1
return circle
}
else
{
return nil
}
}
I ended up using the CLRegion.containsCoordinate(location.coordinate) method instead. It works pretty much the same way.
Once the object has entered my set region, it returns true and from here I can know when it's entered and exited the region.
Please ensure [CLLocationManager regionMonitoringAvailable] returns YES and
CLLocationManager.monitoredRegions contains valid regions.
Also, from Apple documentation:
In iOS 6, regions with a radius between 1 and 400 meters work better
on iPhone 4S or later devices. (In iOS 5, regions with a radius
between 1 and 150 meters work better on iPhone 4S and later devices.)
On these devices, an app can expect to receive the appropriate region
entered or region exited notification within 3 to 5 minutes on
average, if not sooner.
And
Apps can expect a notification as soon as the device moves 500 meters
or more from its previous notification. It should not expect
notifications more frequently than once every five minutes. If the
device is able to retrieve data from the network, the location manager
is much more likely to deliver notifications in a timely manner.
There are many causes why your delegates are not triggering. First goto target settings and in capabilities tab check whether in BackgroundModes Location Updates is enabled.
If it is on then try to check whether your current location manager holds the region you've specified by checking
NSLog(#"Monitored Regions %#",self.locationManager.monitoredRegions);
Then if the user device is at current location(Latitude and longitude) the didEnterRegion: and didExitRegion: delegates will not be triggering. Use didDetermineState: method to find whether the user/device is in current region that is moniotred. If it so, didDetermineState: will be triggered. Once the user leaves the region didExitRegion: will be triggered.
Then after also if delegates aren't trigerring then find then error using the following in delegate
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
NSLog(#"Failed to Monitor %#", error);
}

Update location only once

I am adding a mapKit for my app, and I setting the middle of the map to be the persons current location, in lat and lng. I am able to get it working, however, it keeps updating every so often. I only want it to update once when the app is loaded, then not update anymore. Maybe update every 2 minutes. Here is my code:
func locationManager(manager: CLLocationManager!,
didUpdateLocations locations: [AnyObject]!)
{
var latestLocation = locations.last as! CLLocation
let location = CLLocationCoordinate2D(latitude: latestLocation.coordinate.latitude, longitude: latestLocation.coordinate.longitude)
let span = MKCoordinateSpanMake(0.015, 0.015)
//Let our point be the center of our span
//region holds value of span and location
let region = MKCoordinateRegion(center: location, span: span)
//set up region on mapView
mapView.setRegion(region, animated: true)
//MKPointAnnotation defines a concrete annotation
let annotation = MKPointAnnotation()
}
If you are targeting only iOS 9, look at the new requestLocation() method. It addresses your problem. If you need to target older versions of iOS, you could add stopMonitoringLocation() to the
func locationManager(
manager: CLLocationManager!,
didUpdateLocations locations: [AnyObject]!
)
This will stop the monitoring once you get one reading...
I'm not sure what your starting you location manager with, but I think you might want to look at using:
startMonitoringSignificantLocationChanges()
to start your location manager. Here is apple's documentation on the subject: https://developer.apple.com/library/prerelease/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/index.html#//apple_ref/occ/instm/CLLocationManager/startMonitoringSignificantLocationChanges

Resources