Get started with Positioning
- Last UpdatedApr 28, 2025
- 10 minute read
One of the main reasons to use a mapping application is to find out where you are.
The LocationEngine
provided by the HERE SDK implements a comprehensive location solution that works with several location sources such as GPS or other Global Navigation Satellite System (GNSS) receivers, mobile network signals and Wi-Fi network signals to determine accurate locations.
If an iOS device itself is capable of GNSS precision depends on the hardware of the iOS device. Sub-meter accuracy is currently not supported by iOS and would require a separate receiver. For Android devices sub-meter accuracy is only supported when your credentials are enabled for this (see below).
Integrating the HERE SDK location features requires at least the following steps:
- Add the required permissions to your manifest file (for Android) and your
.plist
file (for iOS) and request the permissions from the user. - Create a
LocationEngine
and set at least oneLocationListener
. - If it is the first launch of the application on Android, inform application user about the collection of characteristics info of near-by mobile and Wi-Fi network signals and make a link to the related HERE Privacy Notice available to the user. An example of how this may be done via application’s Privacy Policy is presented in this example app.
- On Android confirm that the previous step is done by calling the method
confirmHEREPrivacyNoticeInclusion()
. - Start the
LocationEngine
once and set the desired accuracy level. - Receive
Location
updates and handle them in your app.
Add permissions
Flutter itself provides no permission handling. Therefore, you need to adapt a few generated files for your Android and iOS native projects.
Let's start with Android.
Before you can start using the LocationEngine
in your app on Android devices, you will need to add the required permissions to the app's AndroidManifest.xml
file (located in YOUR_PROJECT_DIRECTORY/android/app/src/main/
):
Note
If your application targets Android SDK version 31 or higher, users of your application need to grant the device's "precise" location. When being prompted, it is not enough to select the "approximate" precision. Therefore,
ACCESS_COARSE_LOCATION
andACCESS_FINE_LOCATION
permissions need to be present in your manifest file, as shown above. HERE positioning needs the fine location permission in order to use GNSS and to make cellular and WiFi scans. TheACCESS_COARSE_LOCATION
permission alone is not enough as it would result in an approximate precision which is not enough for HERE positioning to work. In that case, theLocationEngine
would fail with aMISSING_PERMISSIONS
error.The
WAKE_LOCK
permission is not enforced by the HERE SDK, however, if the permission is granted for the application, HERE SDK will use wake locks to ensure that network scans and position calculation are not interrupted by the device going in power save mode. Wake locks are kept only for minimum required time to keep impact on battery consumption as low as possible. It should be noted that Android operating system blames the battery consumption to the application or service that is keeping a wake lock for its duration, so to keep your application appealing for the users you should carefully consider whether wake locks are mandatory for your use case or not.
Next, we can move on to iOS.
Add to the app's Info.plist
file (located in YOUR_PROJECT_DIRECTORY/ios/Runner/
):
Note
Note that permission
NSLocationAlwaysAndWhenInUseUsageDescription
is needed only if your application wants to request location updates while on background.
The permission_handler plugin can be used to request specific permissions from the user. Please refer to the plugin's official site for more information. Alternatively, you can find platform specific code for requesting permissions in the "Find your Location" section of the Developer Guide for the HERE SDK for Android and Developer Guide for the HERE SDK for iOS.
Not all devices provide the same capabilities and may have certain hardware restrictions that can lead to differences in positioning precision.
Note
Even recent iPad or Android tablet devices can lack the required
UIRequiredDeviceCapabilities
forgps
. If present in theInfo.plist
file, the app will not install on such devices: if you remove this capability, the app will install, but theLocation
updates you will receive from the device will have a larger accuracy radius and are therefore quite imprecise - if there is no GPS receiver, the device may fall back to, for example, network positioning.
Prior to using the LocationEngine
, it may be a good idea to check if the native location functionality is enabled. On most Android devices a user can decide to turn the location functionality on, and even increase the accuracy, by opening the device's Settings and navigating to the Security & location section. On most iOS devices, a user can navigate to Settings -> Privacy -> Location Services to make sure that the location functionality is on.
Initialize the LocationEngine
Creating a new LocationEngine
is simple:
Note
It is not possible to initialize the
LocationEngine
during theApplication
'sonCreate()
lifecycle. Any other point in time is fine. For example, a good place to initialize the engine may be in anActivity
'sonCreate()
-method.
Confirm handling of HERE Privacy notice
On Android devices the LocationEngine
occasionally collects information about the characteristics of mobile and Wi-Fi network signals surrounding the mobile device in order to maintain, improve, and provide HERE Positioning services used by the HERE SDK. For example, this includes the strength of nearby signals. HERE has a legitimate interest in collecting this information to maintain, improve, and provide location services. The collected information does not identify the user, and HERE will only retain anonymized data. For more details, please see the HERE Privacy Notice. As of now, on iOS devices, the HERE SDK will not collect any data.
Note
By default, on Android devices, the app needs to call
locationEngine.confirmHEREPrivacyNoticeInclusion()
as a confirmation that collection of characteristics info of near-by mobile and Wi-Fi network signals is described in the application's Terms & Conditions, or Privacy Policy, or otherwise made available to the user, with a reference to the HERE Privacy Notice. See the Legal requirement section below for more information and an example text snippet.In special cases pre-approved by HERE, such as when the app solely targets children, the app can call
locationEngine.confirmHEREPrivacyNoticeException()
to confirm that an exceptional permission has been granted by HERE. Consequently, data collection will not take place, and a reference to the HERE Privacy Notice is not required. If you believe data collection should be disabled for your use case, please contact your HERE account executive.The
LocationEngine
will be fully functional after calling either of the aforementioned methods. Note that this is only necessary on Android devices as on iOS devices no data will be collected.
Before starting the LocationEngine
, you need to confirm that the HERE Privacy Notice is handled by calling locationEngine.confirmHEREPrivacyNoticeInclusion()
(or by calling locationEngine.confirmHEREPrivacyNoticeException()
, if HERE has granted an exception – see the note above).
If you are calling the LocationEngine
's start()
method on Android devices without calling locationEngine.confirmHEREPrivacyNoticeInclusion()
or locationEngine.confirmHEREPrivacyNoticeException()
beforehand then the engine will not provide location updates. When calling locationEngine.confirmHEREPrivacyNoticeException()
the permission for the exception will be verified asynchronously using your HERE SDK credentials. A missing permission will stop the LocationEngine
and a registered LocationStatusListener
will be notified with a LocationEngineStatus.PRIVACY_NOTICE_UNCONFIRMED
status.
Receive locations
Once the engine is initialized, the last known location can be obtained, as long as the engine has been started at least once before and received at least one position, otherwise null
will be returned. This information will remain, so the last known location will also be available between application sessions.
Note
Note that the
LocationEngine
does not need to be started nor any listener needs to be set in order to get the last known location. TheLocation
object contains atimestamp
that indicates when that location was received.
Next, before starting the LocationEngine
, it's a good idea to register a LocationStatusListener
so that you will be notified of changes in the engine's status. To do so, implement the LocationStatusListener
abstract class and register it with the location engine's addLocationStatusListener()
method. Check the API Reference for more information on the different statuses.
Note
After a successful start,
LocationStatusListener
will always receive statusLocationEngineStatus.engineStarted
, and after a successful stop, it will always receive statusLocationEngineStatus.engineStopped
.
Additionally, through the listener's onFeaturesNotAvailable()
callback you will be notified of any LocationFeature
that is not available. If a feature that you need is not available, contact your HERE representative.
The last thing to consider before starting the engine is registering a LocationListener
, which provides the onLocationUpdated()
callback that sends a notification once a new Location
is detected. You can do so in a similar way as with the previously mentioned LocationStatusListener
:
Note
The callback
onLocationUpdated()
is received on the main thread - same as for all other callbacks.
Except for the current geographic coordinates and the timestamp, all other Location
fields are optional. For example, the received Location
object may contain the information about the bearing angle, as well as the current speed, but this is not guaranteed to be available. Unavailable values will be returned as null
.
You can add as many LocationStatusListener
and LocationListener
as you need by calling the respective addLocationStatusListener()
and addLocationListener()
methods.
For more detailed information about positioning issues, implement the LocationIssueListener
interface and register it with the location engine's addLocationIssueListener()
method. Via this interface location engine delivers events describing the cause of error when the location engine is running. Check the API Reference for more information on the different issues.
You are now ready to call the LocationEngine
's startWithLocationAccuracy()
method:
The most straightforward way to start the engine is by passing it one of the pre-defined LocationAccuracy
modes, as in the code snippet above. See the table below or check the API Reference for more information about all the available modes.
After the LocationEngine
has been started, you will receive LocationEngineStatus.alreadyStarted
if you try to start it again without calling stop()
first. You can use the method isStarted()
to check if the engine is started or not. Similarly, if you have started a LocationEngine
and try to start another one without stopping the first, you will get LocationEngineStatus.alreadyStarted
error. Only one engine can be started at a time.
If you don't want to receive more location updates, you can stop the engine by calling the stop()
method. Remember to remove the listeners when they are no longer needed:
In general, it is recommended to listen to the AppLifecycleState
and to stop the LocationEngine
when an app gets disposed, see the positioning_app
for an example on GitHub.
Pause updates while stationary on iOS devices
On iOS devices the LocationEngine
will, by default, pause the location updates when location data is not expected to change. This can be used, for example, to improve battery life when the device is stationary. This feature can be controlled by the method LocationEngine.setPauseLocationUpdatesAutomatically()
.
Note
On Android platforms,
setPauseLocationUpdatesAutomatically()
will returnLocationEngineStatus.notSupported
.
Show your location on the map
A LocationIndicator
is used for representing device's current location on map. Before the indicator is updated with a current location value, a default Location
is set, which can be the last known location - or just any place the user should see before the first location update arrives. By default, the horizontal accuracy is visualized with a MapCircle
that has a radius of horizontalAccuracyInMeters
.
As shown in the implementation above, you can pass the Location
object to the location indicator by calling updateLocation()
. In this example, the goal is to track the user's current location - therefore, the map viewport's center location is updated as well.
Simulate location updates during development on Simulator/Emulator
iOS Simulator
- Launch the iOS Simulator.
- In the top menu bar, go to Features -> Location -> Custom Location.
- Add the desired location(s).
Android Emulator
- Launch the Android Emulator.
- Open Extended Controls by clicking the three dots menu on the emulator window.
- Go to the Location tab.
- Add the desired location(s).
Try the Positioning example apps
- On GitHub you can find the "positioning_app" example app covering most code snippets shown above.
- The HikingDiary app shows how to record GPX traces.
Legal requirement
It is the application developer's responsibility to inform users about the collection of nearby mobile and Wi-Fi network signal characteristics. Additionally, developers must provide users with a link to the relevant HERE Privacy Notice.
This information may be included in the application's Terms & Conditions or Privacy Policy, or otherwise made available to the user. An example text for informing users about data collection is shown below:
"This application uses location services provided by HERE Technologies. To maintain, improve and provide these services, HERE Technologies from time to time gathers characteristics information about the near-by network signals. For more information, please see the HERE Privacy Notice at https://legal.here.com/here-network-positioning-via-sdk"
Note
Note that this requirement only applies to Android applications, as currently there is no data collection in iOS. This might change in the future.