Getting Location Information using the iOS 11 Core Location Framework


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book


iOS devices are able to employ a number of different techniques for obtaining information about the current geographical location of the device. These mechanisms include GPS, cell tower triangulation and finally (and least accurately), by using the IP address of available Wi-Fi connections. The mechanism that is used by iOS to detect location information is, however, largely transparent to the application developer and the system will automatically use the most accurate solution available at any given time. In fact, all that is needed to integrate location based information into an iOS application is an understanding of how to use the Core Location Framework which, incidentally, is the subject of this chapter.

Once the basics of location tracking with Core Location have been covered in this chapter, the next chapter will provide detailed steps on how to create An Example iOS 11 Location Application.

The Core Location Manager

The key classes contained within the Core Location Framework are CLLocationManager and CLLocation. An instance of the CLLocationManager class can be created using the following Swift code:

var locationManager: CLLocationManager = CLLocationManager()

Once a location manager instance has been created, it must seek permission from the user to collect location information before it can begin to track data.

Requesting Location Access Authorization

Before any application can begin to track location data it must first seek permission to do so from the user. This can be achieved by making a call to one of two methods on the CLLocationManager instance depending on the specific requirement. If the application only needs to track location information when the application is in the foreground then a call should be made to the requestWhenInUseAuthorization method of the location manager instance. For example:

locationManager.requestWhenInUseAuthorization()

In the event that tracking is also required when the application is running in the background, the requestAlwaysAuthorization method should be called:

locationManager.requestAlwaysAuthorization()

If an app requires always authorization, the recommended path to requesting this permission is to first seek when in use permission and to then offer the user the opportunity to elevate this permission to always mode at the point that it is needed by the app. The reasoning behind this recommendation is that when seeking always permission, the request dialog displayed by iOS will provide the user the option of using either when in use or always location tracking. Given these choices, most users will typically select the when in use option. A better approach is to begin by requesting when in use tracking and then explain the benefits of elevating to always mode in a later request.

Both location authorization request method calls require that specific key-value pairs be added to the Information Property List dictionary contained within the application’s Info.plist file. The values take the form of strings and must describe the reason why the application needs access to the user’s current location. The keys associated with these values are as follows:

  • NSLocationWhenInUseUsageDescription – A string value describing to the user why the application needs access to the current location when running in the foreground. This string is displayed when a call is made to the requestWhenInUseAuthorization method of the locationManager instance. The dialog displayed to the user containing this message will only provide the option to permit when in use location tracking. All apps built using the iOS 11 SDK or later must include this key regardless of the usage permission level being requested in order to access the device location.
  • NSLocationAlwaysAndWhenInUseUsageDesciption – The string displayed when permission is requested for always authorization using the requestAlwaysAuthorization method. The request dialog containing this message will provide the user with the choice of selecting either always or when in use authorization. All apps built using the iOS 11 SDK or later must include this key when accessing device location information.
  • NSLocationAlwaysUsageDescription – A string describing to the user why the application needs always access to the current location. This description is not used on devices running iOS 11 or later, though it should still be declared for compatibility with legacy devices.

Configuring the Desired Location Accuracy

The level of accuracy to which location information is to be tracked is specified via the desiredAccuracy property of the CLLocationManager object. It is important to keep in mind when configuring this property that the greater the level of accuracy selected the greater the drain on the device battery. An application should, therefore, never request a greater level of accuracy than is actually needed.

A number of predefined constant values are available for use when configuring this property:

  • kCLLocationAccuracyBestForNavigation – Uses the highest possible level of accuracy augmented by additional sensor data. This accuracy level is intended solely for use when the device is connected to an external power supply.
  • kCLLocationAccuracyBest – The highest recommended level of accuracy for devices running on battery power.
  • kCLLocationAccuracyNearestTenMeters - Accurate to within 10 meters.
  • kCLLocationAccuracyHundredMeters – Accurate to within 100 meters.
  • kCLLocationAccuracyKilometer – Accurate to within one kilometer.
  • kCLLocationAccuracyThreeKilometers – Accurate to within three kilometers.

The following code, for example, sets the level of accuracy for a location manager instance to “best accuracy”:

locationManager.desiredAccuracy = kCLLocationAccuracyBest

Configuring the Distance Filter

The default configuration for the location manager is to report updates whenever any changes are detected in the location of the device. The distanceFilter property of the location manager allows applications to specify the amount of distance the device location must change before an update is triggered. If, for example, the distance filter is set to 1000 meters the application will only receive a location update when the device travels 1000 meters or more from the location of the last update. For example, to specify a distance filter of 1500 meters:

locationManager.distanceFilter = 1500.0

The distance filter may be cancelled, thereby returning to the default setting, using the kCLDistanceFilterNone constant:

locationManager.distanceFilter = kCLDistanceFilterNone

Continuous Background Location Updates

The location tracking options covered so far in this chapter only receive updates when the app is either in the foreground or background. As soon as the app enters the suspended state (in other words the app is still resident in memory but is no longer executing code) the updates will stop. If location updates are required even when the app is suspended (a key requirement for navigation based apps), continuous background location updates must be enabled for the app. When enabled, the app will be woken from suspension each time a location update is triggered and provided the latest location data.

To enable continuous location updates is a two-step process beginning with addition of an entry to the project Info.plist file. This is most easily achieved by enabling the location updates background mode in the Xcode Capabilities panel as shown in Figure 78 1:


Ios 11 enable background location updates.png

Figure 78-1


Within the app code, continuous updates are enabled by setting the allowsBackgroundLocationUpdates property of the location manager to true:

locationManager.allowsBackgroundLocationUpdates = true

To allow the location manager to temporarily suspend updates, set the pausesLocationUpdatesAutomatically property of the location manage to true.

locationManager.pausesLocationUpdatesAutomatically = true

This setting allows the location manager to extend battery life by pausing updates when it is appropriate to do so (for example when the user’s location remains unchanged for a significant amount of time). When the user starts moving again, the location manager will automatically resume updates.

Continuous location background updates are available for apps for both always and when in use authorization modes. When activated for an app that only has when in use authorization, a blue notification bar will appear along the top of the screen, as demonstrated in Figure 78-2:


Ios 11 background location blue bar.png

Figure 78-2

Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book

The Location Manager Delegate

Location manager updates and errors result in calls to two delegate methods defined within the CLLocationManagerDelegate protocol. Templates for the two delegate methods that must be implemented to comply with this protocol are as follows:

func locationManager(_ manager: CLLocationManager,
                didUpdateLocations locations: [CLLocation])
{
   // Handle location updates here
}

func locationManager(_ manager: CLLocationManager,
         didFailWithError error: Error)
{
   // Handle errors here 
}

Each time the location changes, the didUpdateLocations delegate method is called and passed as an argument an array of CLLocation objects with the last object in the array containing the most recent location data.

Changes to the location tracking authorization status of an application are reported via a call to the optional didChangeAuthorization delegate method:

func locationManager(_ manager: CLLocationManager, 
      didChangeAuthorization status: CLAuthorizationStatus) {

    // App may no longer be authorized to obtain location
    //information. Check status here and respond accordingly.
}

Once a class has been configured to act as the delegate for the location manager, that object must be assigned to the location manager instance. In most cases, the delegate will be the same view controller class in which the location manager resides, for example:

locationManager.delegate = self

Starting and Stopping Location Updates

Once suitably configured and authorized, the location manager can then be instructed to start tracking location information:

locationManager.startUpdatingLocation()

With each location update, the didUpdateLocations delegate method is called by the location manager and passed information about the current location.

To stop location updates, simply call the stopUdatingLocation method of the location manager as follows:

locationManager.stopUpdatingLocation()

Obtaining Location Information from CLLocation Objects

Location information is passed through to the didUpdateLocation delegate method in the form of CLLocation objects. A CLLocation object encapsulates the following data:

  • Latitude
  • Longitude
  • Horizontal Accuracy
  • Altitude
  • Altitude Accuracy

Longitude and Latitude

Longitude and latitude values are stored as type CLLocationDegrees and may be obtained from a CLLocation object as follows:

let currentLatitude: CLLocationDistance = 
        location.coordinate.latitude

let currentLongitude: CLLocationDistance = 
        location.coordinate.longitude

Accuracy

Horizontal and vertical accuracy are stored in meters as CLLocationAccuracy values and may be accessed as follows:

let verticalAccuracy: CLLocationAccuracy = 
        location.verticalAccuracy

let horizontalAccuracy: CLLocationAccuracy = 
        location.horizontalAccuracy

Altitude

The altitude value is stored in meters as a type CLLocationDistance value and may be accessed from a CLLocation object as follows:

let altitude: CLLocationDistance = location.altitude

Getting the Current Location

If all that is required from the location manager is the user’s current location without the need for continuous location updates, this can be achieved via a call to the requestLocation method of the location manager instance. This method will identify the current location and call the didUpdateLocations delegate one time passing through the current location information. Location updates are then automatically turned off:

locationManager.requestLocation()

Calculating Distances

The distance between two CLLocation points may be calculated by calling the distance(from:) method of the end location and passing through the start location as an argument. For example, the following code calculates the distance between the points specified by startLocation and endLocation:

var distance: CLLocationDistance = 
	endLocation.distance(from: startLocation)

Summary

This chapter has provided an overview of the use of the iOS Core Location Framework to obtain location information within an iOS application. This theory will be put into practice in the next chapter entitled An Example iOS 11 Location Application.


Learn SwiftUI and take your iOS Development to the Next Level
SwiftUI Essentials – iOS 16 Edition book is now available in Print ($39.99) and eBook ($29.99) editions. Learn more...

Buy Print Preview Book