How to track user location in the background swift - ios

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

Related

How do I track in the background in iOS a user walking and calculate the distance traveled so far using Swift and Xcode?

How do I track in the background in iOS a user walking in Apple MapKit or Google Maps Platform for iOS and calculate the distance traveled so far using Swift and Xcode?
I have tried using MapKit. The problem I get is that when the iOS device is locked, Core Location stops tracking the device. When the device is unlocked and the app comes to the foreground, Core Location starts tracking again and draws a straight line from the last point tracked to the point tracked when the app comes to the foreground, thus skipping all the time that the device is locked. If Google Maps Platform works better for this purpose, I am willing to use it.
Following is the relevant code:
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.allowsBackgroundLocationUpdates = true
if #available(iOS 11.0, *) {
locationManager.showsBackgroundLocationIndicator = true
}
let status = CLLocationManager.authorizationStatus()
if status == .authorizedAlways || status == .authorizedWhenInUse || status == .restricted {
locationManager.startUpdatingLocation()
locationManager.startMonitoringSignificantLocationChanges()
} else {
locationManager.requestAlwaysAuthorization()
}
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedAlways || status == .authorizedWhenInUse || status == .restricted {
locationManager.startUpdatingLocation()
locationManager.startMonitoringSignificantLocationChanges()
} else {
locationManager.requestAlwaysAuthorization()
}
}
Did you add in your .plist,
Privacy - Location Always and When In Use Usage Description and
Privacy - Location When In Use Usage Description?
Then as you are probably conforming CLLocationManagerDelegate in the method didUpdateLocations you should be able to perform your code.
My mistake was that I was creating the line with the user location from the map instead of the user location passed to the didUpdateLocations method. The userLocation property on the map does not update in the background, whereas the userLocation property of CLLocationManager does update in the background.
Here is the corrected code, with a comment on the line that I corrected:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("didUpdateLocations", locations)
if let userLocation = locations.first, polyline != nil {
let userLocationMapPoint = MKMapPoint(userLocation.coordinate)
let lastUserLocationMapPoint = MKMapPoint(route.last!)
totalDistance += userLocationMapPoint.distance(to: lastUserLocationMapPoint)
mapView.removeOverlay(polyline)
route.append(userLocation.coordinate) // changed from route.append(mapView.userLocation.coordinate)
polyline = MKPolyline(coordinates: route, count: route.count)
mapView.addOverlay(polyline)
}
print("latitude:", mapView.userLocation.coordinate.latitude, "longitude:", mapView.userLocation.coordinate.longitude)
}

CLRegionState is coming Unknown while requesting a state from the location manager?

I am building a feature related to region monitoring while starting region monitoring I am requesting the state as shown below in code. On some of the devices, I am getting region state Unknown all the time. If I switch Wifi On or Off or plug the charger into it. It starts working fine.
How can I make it more reliable on a cellular network?
Please, note I took all location permissions from the user before making any region monitoring or state request calls.
private func initiateLocationManager() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.distanceFilter = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
}
func startMonitoring(alarm: StationAlarm) {
if LocationManager.sharedInstance.isRegionMonitoringAvailable() {
let coordinate = CLLocationCoordinate2D(latitude: stationLatitude, longitude: stationLongitude)
// 1
let region = CLCircularRegion(center: coordinate, radius: CLLocationDistance(radius * 1000), identifier: alarm.alarmId)
// 2
region.notifyOnEntry = true
region.notifyOnExit = false
// 4
locationManager.startMonitoring(for: region)
Utility.delay(0.1) { [weak self] in
self?.locationManager.requestState(for: region)
}
}
}
func locationManager(_: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
Log.event("Region State is \(state.rawValue)")
}
The issue is, you are calling the requestState using a hard-coded delay - (0.1). How do you make sure the Location Manager started monitoring your region within 0.1 seconds? You will get the exact region state of a region, only if started monitoring it.
The better method for overcoming this problem is, implement the didStartMonitoringForRegion delegate and call requestStateForRegion
locationManager.startMonitoring(for: region)
func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
manager.requestState(for: region)
}
func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
if (region is CLBeaconRegion) && state == .inside {
locationManager(manager, didEnterRegion: region)
}
}
From the CLLocationManager requestState(for:) docs:
region: The region whose state you want to know. This object must be an instance of one of the standard region subclasses provided by Map Kit. You cannot use this method to determine the state of custom regions you define yourself.
You defined the region yourself so you can't use requestState(for:) to get its state. You use that function with regions that you get back from Core Location (via the delegate methods).
If you want to know whether the device is currently inside a region, start a standard location update request (startUpdatingLocation() etc) and when you get back a recent and accurate coordinate, use the CLCircularRegion contains() function to check the coordinate.
// In the locationManager(_:didUpdateLocations:) delegate method
if myCircularRegion.contains(myCoordinate) {
// ...
}

Background Location Updates not working on device alone, but works when device is linked to Xcode [Swift 3.0 - Xcode 8]

When the app is in the foreground, the location updates every second and works perfectly, which is what I want. But when the app is in the background (or in suspended state, I'm not sure), I do not get any local notifications(Ive tested the local notifications on the phone alone, so this isn't the problem). I use local notifications to tell me if the location has been updated, which is how I know the location isn't being updated.
I've set up the background capabilities and info.plist i.e "Privacy - Location When in Use Usage Description" etc. And I've added the below commands.
All my code is in view controllers, not appdelegate, is this my problem?
Note: this works in the background on simulator and on a real device when the device is linked to a laptop with Xcode, and the app is launched from Xcode. It does not work on a real device by itself.
class ViewController: UIViewController, CLLocationManagerDelegate{
let manager = CLLocationManager()
#IBOutlet weak var map: MKMapView!
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let span:MKCoordinateSpan = MKCoordinateSpanMake(0.01,0.01) //shows the size of map screen
let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude,location.coordinate.longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, span)
map.setRegion(region, animated: true)
self.map.showsUserLocation = true
print("Location Updated")
}
override func viewDidLoad() {
super.viewDidLoad()
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.requestAlwaysAuthorization()
manager.startUpdatingLocation()
manager.delegate = self
manager.allowsBackgroundLocationUpdates = true
manager.pausesLocationUpdatesAutomatically = false
}
}
Can someone please help? This is one of the last issues I need to solve for one of my projects. Any links or working Github projects would be greatly appreciated! I just cant figure this one out!

Get user current location(lat/long) in all app state not always only when My app required without location manager delegate

I am working on watch heart beat app and I want when user heart rate critical then we will get his current location in(foreground, background and terminate) and send it to our server. Is there any way through which I get user location only at that position. I don't want to update his location every time.
To get user location you have to declare :
let locationManager = CLLocationManager()
in your controller.
Then, in viewDidLoad you have to request for location and initialize the CLLocationManager get process :
// Ask for Authorisation from the User.
self.locationManager.requestAlwaysAuthorization()
// For use in foreground
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
You will get location in CLLocationManagerDelegate :
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
var location:CLLocationCoordinate2D = manager.location.coordinate
print("locations = \(location.latitude) \(location.longitude)")
}
In your info.plist you have to add NSLocationAlwaysUsageDescription and custom alert message to show while requesting for location.
cheers...

Swift GeoPoint get ALL users location 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.

Resources