Find Your Location
When building location-aware applications, one of the most common tasks is to show the current location of the user on a map. For this, there are many different solutions available. One possible way is to use Apple's CoreLocation
to get locations from the device's built-in GPS sensors.
The HERE SDK works smoothly with any proprietary positioning solution. In the future, a comprehensive HERE positioning solution is planned with more advanced features. A possible platform dependent implementation is shown below.
Before accessing the device's sensors, you need to ask the user for permission. Add the following permissions to your Info.plist
file:
<key>NSLocationWhenInUseUsageDescription</key>
<string>This app needs to access your current location to display it on the map while the app is being used.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>This app needs to access your current location to display it on the map while the app is being used or when running in background.</string>
Next, get an instance of the CLLocationManager
from the iOS platform and request location updates:
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
To receive events, our class needs to conform to the CLLocationManagerDelegate
protocol:
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
guard let lastLocation = locations.last else {
print("Warning: No last location found")
return
}
delegate?.onLocationUpdated(location: lastLocation)
}
delegate
is of type PlatformPositioningProviderDelegate
. This is a protocol we have defined to enable another class to easily get notified.
This is just an example of how to integrate a CLLocationManager
that provides access to the iOS location services. Feel free to adapt it to your own needs.
Below you can find the complete class:
import CoreLocation
import Foundation
import UIKit
public protocol PlatformPositioningProviderDelegate {
func onLocationUpdated(location: CLLocation)
}
class PlatformPositioningProvider : NSObject,
CLLocationManagerDelegate {
var delegate: PlatformPositioningProviderDelegate?
private let locationManager = CLLocationManager()
func startLocating() {
if locationManager.delegate == nil {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
}
}
func stopLocating() {
locationManager.stopUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager,
didChangeAuthorization status: CLAuthorizationStatus) {
switch status {
case .restricted, .denied, .notDetermined:
print("Positioning denied by user.")
break
case .authorizedWhenInUse, .authorizedAlways:
print("Positioning authorized by user.")
locationManager.startUpdatingLocation()
break
default:
break
}
}
func locationManager(_ manager: CLLocationManager,
didFailWithError error: Error) {
if let error = error as? CLError, error.code == .denied {
print("Positioning denied by user.")
manager.stopUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
guard let lastLocation = locations.last else {
print("Warning: No last location found")
return
}
delegate?.onLocationUpdated(location: lastLocation)
}
}
To integrate this class in your own app, create a new instance and set the calling class as delegate:
platformPositioningProvider = PlatformPositioningProvider()
platformPositioningProvider.delegate = self
By setting the calling class as delegate, you need to conform to the PlatformPositioningProviderDelegate
protocol and your class can start to receive CLLocation
events:
func onLocationUpdated(location: CLLocation) {
}
You can then start and stop locating by calling the following methods:
platformPositioningProvider.startLocating()
platformPositioningProvider.stopLocating();
Note that our class receives CLLocation
events. Use the following method to convert them to the Location
class used by the HERE SDK to cover the most common fields:
private func convertLocation(nativeLocation: CLLocation) -> Location {
let geoCoordinates = GeoCoordinates(latitude: nativeLocation.coordinate.latitude,
longitude: nativeLocation.coordinate.longitude,
altitude: nativeLocation.altitude)
var location = Location(coordinates: geoCoordinates,
timestamp: nativeLocation.timestamp)
location.bearingInDegrees = nativeLocation.course < 0 ? nil : nativeLocation.course
location.speedInMetersPerSecond = nativeLocation.speed < 0 ? nil : nativeLocation.speed
location.horizontalAccuracyInMeters = nativeLocation.horizontalAccuracy < 0 ? nil : nativeLocation.horizontalAccuracy
location.verticalAccuracyInMeters = nativeLocation.verticalAccuracy < 0 ? nil : nativeLocation.verticalAccuracy
return location
}
For more information on the CLLocationManager
and how to utilize other platform positioning features, please refer to the official iOS documentation.