Get Started with the Navigation SDK for Android
This guide describes the steps to install the latest version of the Mapbox Navigation SDK for Android, configure your Android app to use the SDK, and run a minimal example showing turn-by-turn navigation.
Prerequisites
- A Mapbox account: Sign up or log into a free account on Mapbox.
- Android Studio: This guide includes details specific to the latest version of Android Studio.
- Gradle: Make sure you have Gradle installed.
Part 1: Configure credentials
Step 1: Create a secret token
A secret access token is required to download the SDK dependencies in your Android project. This token is used by gradle to authenticate with the Mapbox maven server where the SDK packages are hosted.
To create a secret token, follow these steps:
- Go to your account's tokens page.
- Click the Create a token button.
- Name your token, for this example we've used InstallTokenAndroid.
- Scroll down to the Secret Scope section and check the
Downloads:Read
scope box. - Click the Create token button at the bottom of the page to create your token.
- Enter your password to confirm the creation of your token.
- Now, you'll be returned to your account's tokens page, where you can copy your created token. Note, this token is a secret token, which means you will only have one opportunity to copy it, so save this token somewhere secure.
You should not expose secret access tokens in publicly-accessible source code where unauthorized users might find them. Instead, you should store them somewhere safe on your computer and take advantage of Gradle properties to make sure they're only added when your app is compiled.
Step 2: Configure your secret token
Next, add your secret token to your global gradle.properties
file. The global gradle.properties
file is located in your Gradle user home folder.
If you don't have a gradle.properties
file, create one. Add your secret token to the gradle.properties
file as shown below, replacing the placeholder YOUR_SECRET_MAPBOX_ACCESS_TOKEN
with your secret token.
MAPBOX_DOWNLOADS_TOKEN=YOUR_SECRET_MAPBOX_ACCESS_TOKEN
Step 3: Configure your public token
Your app must have a public access token configured to associate its usage of Mapbox resources with your account.
Follow these steps to add a public access token from your Mapbox account as an Android string resource.
- Open your project folder or create a new project in Android Studio.
- If creating a new project, we recommend using the
Empty Activity
project type.
- Locate the resource folder:
- In the project explorer, open your resource folder located at
app/res/values
.
- Create a new resource file:
- Left click on the resource folder
- Select
New
>Values Resource File
- Name the file
mapbox_access_token.xml
- Click the
Ok
button.
- In the new file, copy and paste the code snippet below.
- Make sure you are signed in to docs.mapbox.com. This will insert your default public token into the code snippet (a long string that starts with
pk.
). - If you are not signed in, you will need to replace the placeholder
YOUR_MAPBOX_ACCESS_TOKEN
with a token from your account's tokens page.
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<string name="mapbox_access_token" translatable="false" tools:ignore="UnusedResources">YOUR_MAPBOX_ACCESS_TOKEN</string>
</resources>
Your public access token is now available for use in your Android project. You will access it via the string resource you created in your implementation code.
Advanced Topics: Best Practices, Rotating Tokens & Adding Tokens at Runtime
Step 4: Understand permissions
Real-time navigation requires access to the user's location, access to the network, and access to notify the user of updates. The SDK already includes all necessary permissions in its AndroidManifest.xml
file, and these will be merged with any permissions you have in your app's manifest file via Manifest Merging.
You do not need to add any additional permissions to your app's manifest file, but you should make sure that your app requests the necessary permissions at runtime. The SDK provides a PermissionsManager
class to help you manage permissions. You can check whether the user has granted location permission and request permissions if the user hasn't granted them yet using the PermissionsManager
.
The permissions used by the SDK are listed below:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
If your app targets Android 13 or higher, the POST_NOTIFICATIONS
permission is required to show notifications to the user. The SDK shows the notifications during both Free Drive and Active Guidance if you don't explicitly disable the foreground service launch by calling MapboxNavigation#startTripSession(false)
.
The notification contains some useful trip progress information and UI controls, so it is highly recommended that you request the permission in runtime.
Part 2: Add the Dependency
Step 1: Add the Mapbox Maven repository
Mapbox provides the Maps SDK dependencies via a private Maven repository. To download Mapbox dependencies, you must add the Maven repository's URL to your project.
- In Android Studio, under Gradle Scripts, open the
settings.gradle
file. - Add a new
maven {...}
definition insidedependencyResolutionManagement.repositories
.
This configuration uses the secret access token you configured in Part 1 to authenticate with the Mapbox Maven repository.
Step 2: Add Nav SDK dependencies
Next, add Nav SDK modules to your project.
-
In Android Studio, open your module-level
build.gradle
file. -
Add the Navigation SDK dependencies under
dependencies
.
You can add the full SDK with a single dependency by adding the android
module:
dependencies {
...
implementation "com.mapbox.navigationcore:android:3.7.0"
...
}
dependencies {
...
implementation("com.mapbox.navigationcore:android:3.7.0")
...
}
You can also include individual modules based on your app's requirements:
Module | Description |
---|---|
com.mapbox.navigationcore:copilot | The Copilot is a component that collects detailed trace files of navigation sessions together with search analytics data. |
com.mapbox.navigationcore:ui-maps | The Maps component provides a set of classes that can enhance the navigation experience for your users, for example, Navigation Camera to simplify management of the map's camera object, or Route Line to render a route line on a map. |
com.mapbox.navigationcore:navigation | The Navigation module is the primary interface for engaging with the Navigation SDK. |
com.mapbox.navigationcore:tripdata | The Trip Data component provides convenient API to request maneuver instructions, route shields, speed limit, and trip progress data. |
com.mapbox.navigationcore:ui-components | The UI components module provides pre-built UI widgets. |
com.mapbox.navigationcore:voice | The Voice component allows users to access Voice API. |
dependencies {
...
implementation "com.mapbox.navigationcore:navigation:3.7.0"
implementation "com.mapbox.navigationcore:copilot:3.7.0"
implementation "com.mapbox.navigationcore:ui-maps:3.7.0"
implementation "com.mapbox.navigationcore:voice:3.7.0"
implementation "com.mapbox.navigationcore:tripdata:3.7.0"
implementation "com.mapbox.navigationcore:android:3.7.0"
implementation "com.mapbox.navigationcore:ui-components:3.7.0"
...
}
dependencies {
...
implementation("com.mapbox.navigationcore:navigation:3.7.0")
implementation("com.mapbox.navigationcore:copilot:3.7.0")
implementation("com.mapbox.navigationcore:ui-maps:3.7.0")
implementation("com.mapbox.navigationcore:voice:3.7.0")
implementation("com.mapbox.navigationcore:tripdata:3.7.0")
implementation("com.mapbox.navigationcore:android:3.7.0")
implementation("com.mapbox.navigationcore:ui-components:3.7.0")
...
}
- Make sure that your project's
minSdk
is 21 or higher:
android {
...
defaultConfig {
minSdk 21
...
}
}
android {
...
defaultConfig {
minSdk = 21
...
}
}
Part 3: Run a Navigation Example
To confirm that the Navigation SDK dependencies are correctly installed and your tokens are configured properly, add sample code to your app to run a turn-by-turn navigation with simulated user locations.
This android activity includes a scaled-down navigation experience with a map, route line, and location puck.
Follow these steps in your Android Studio project:
- Add the sample code below to your
MainActivty.kt
file.
package com.example.myapplication
import android.Manifest
import android.annotation.SuppressLint
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.app.ActivityCompat
import com.mapbox.api.directions.v5.models.RouteOptions
import com.mapbox.common.location.Location
import com.mapbox.geojson.Point
import com.mapbox.maps.CameraOptions
import com.mapbox.maps.EdgeInsets
import com.mapbox.maps.MapView
import com.mapbox.maps.plugin.LocationPuck2D
import com.mapbox.maps.plugin.animation.camera
import com.mapbox.maps.plugin.locationcomponent.createDefault2DPuck
import com.mapbox.maps.plugin.locationcomponent.location
import com.mapbox.navigation.base.ExperimentalPreviewMapboxNavigationAPI
import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions
import com.mapbox.navigation.base.options.NavigationOptions
import com.mapbox.navigation.base.route.NavigationRoute
import com.mapbox.navigation.base.route.NavigationRouterCallback
import com.mapbox.navigation.base.route.RouterFailure
import com.mapbox.navigation.core.MapboxNavigation
import com.mapbox.navigation.core.directions.session.RoutesObserver
import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp
import com.mapbox.navigation.core.lifecycle.MapboxNavigationObserver
import com.mapbox.navigation.core.lifecycle.requireMapboxNavigation
import com.mapbox.navigation.core.replay.route.ReplayProgressObserver
import com.mapbox.navigation.core.replay.route.ReplayRouteMapper
import com.mapbox.navigation.core.trip.session.LocationMatcherResult
import com.mapbox.navigation.core.trip.session.LocationObserver
import com.mapbox.navigation.ui.maps.camera.NavigationCamera
import com.mapbox.navigation.ui.maps.camera.data.MapboxNavigationViewportDataSource
import com.mapbox.navigation.ui.maps.location.NavigationLocationProvider
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineApi
import com.mapbox.navigation.ui.maps.route.line.api.MapboxRouteLineView
import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineApiOptions
import com.mapbox.navigation.ui.maps.route.line.model.MapboxRouteLineViewOptions
class MainActivity : ComponentActivity() {
private lateinit var mapView: MapView
private lateinit var viewportDataSource: MapboxNavigationViewportDataSource
private lateinit var navigationCamera: NavigationCamera
private lateinit var routeLineApi: MapboxRouteLineApi
private lateinit var routeLineView: MapboxRouteLineView
private lateinit var replayProgressObserver: ReplayProgressObserver
private val navigationLocationProvider = NavigationLocationProvider()
private val replayRouteMapper = ReplayRouteMapper()
// Activity result launcher for location permissions
private val locationPermissionRequest =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
permissions ->
when {
permissions[Manifest.permission.ACCESS_COARSE_LOCATION] == true -> {
initializeMapComponents()
}
else -> {
Toast.makeText(
this,
"Location permissions denied. Please enable permissions in settings.",
Toast.LENGTH_LONG
)
.show()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// check/request location permissions
if (
ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) ==
PackageManager.PERMISSION_GRANTED
) {
// Permissions are already granted
initializeMapComponents()
} else {
// Request location permissions
locationPermissionRequest.launch(arrayOf(Manifest.permission.ACCESS_COARSE_LOCATION))
}
}
private fun initializeMapComponents() {
// create a new Mapbox map
mapView = MapView(this)
mapView.mapboxMap.setCamera(
CameraOptions.Builder()
.center(Point.fromLngLat(-122.43539772352648, 37.77440680146262))
.zoom(14.0)
.build()
)
// Initialize location puck using navigationLocationProvider as its data source
mapView.location.apply {
setLocationProvider(navigationLocationProvider)
locationPuck = LocationPuck2D()
enabled = true
}
setContentView(mapView)
// set viewportDataSource, which tells the navigationCamera where to look
viewportDataSource = MapboxNavigationViewportDataSource(mapView.mapboxMap)
// set padding for the navigation camera
val pixelDensity = this.resources.displayMetrics.density
viewportDataSource.followingPadding =
EdgeInsets(
180.0 * pixelDensity,
40.0 * pixelDensity,
150.0 * pixelDensity,
40.0 * pixelDensity
)
// initialize a NavigationCamera
navigationCamera = NavigationCamera(mapView.mapboxMap, mapView.camera, viewportDataSource)
// Initialize route line api and view for drawing the route on the map
routeLineApi = MapboxRouteLineApi(MapboxRouteLineApiOptions.Builder().build())
routeLineView = MapboxRouteLineView(MapboxRouteLineViewOptions.Builder(this).build())
}
// routes observer draws a route line and origin/destination circles on the map
private val routesObserver = RoutesObserver { routeUpdateResult ->
if (routeUpdateResult.navigationRoutes.isNotEmpty()) {
// generate route geometries asynchronously and render them
routeLineApi.setNavigationRoutes(routeUpdateResult.navigationRoutes) { value ->
mapView.mapboxMap.style?.apply { routeLineView.renderRouteDrawData(this, value) }
}
// update viewportSourceData to include the new route
viewportDataSource.onRouteChanged(routeUpdateResult.navigationRoutes.first())
viewportDataSource.evaluate()
// set the navigationCamera to OVERVIEW
navigationCamera.requestNavigationCameraToOverview()
}
}
// locationObserver updates the location puck and camera to follow the user's location
private val locationObserver =
object : LocationObserver {
override fun onNewRawLocation(rawLocation: Location) {}
override fun onNewLocationMatcherResult(locationMatcherResult: LocationMatcherResult) {
val enhancedLocation = locationMatcherResult.enhancedLocation
// update location puck's position on the map
navigationLocationProvider.changePosition(
location = enhancedLocation,
keyPoints = locationMatcherResult.keyPoints,
)
// update viewportDataSource to trigger camera to follow the location
viewportDataSource.onLocationChanged(enhancedLocation)
viewportDataSource.evaluate()
// set the navigationCamera to FOLLOWING
navigationCamera.requestNavigationCameraToFollowing()
}
}
// define MapboxNavigation
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
private val mapboxNavigation: MapboxNavigation by
requireMapboxNavigation(
onResumedObserver =
object : MapboxNavigationObserver {
@SuppressLint("MissingPermission")
override fun onAttached(mapboxNavigation: MapboxNavigation) {
// register observers
mapboxNavigation.registerRoutesObserver(routesObserver)
mapboxNavigation.registerLocationObserver(locationObserver)
replayProgressObserver =
ReplayProgressObserver(mapboxNavigation.mapboxReplayer)
mapboxNavigation.registerRouteProgressObserver(replayProgressObserver)
mapboxNavigation.startReplayTripSession()
}
override fun onDetached(mapboxNavigation: MapboxNavigation) {}
},
onInitialize = this::initNavigation
)
// on initialization of MapboxNavigation, request a route between two fixed points
@OptIn(ExperimentalPreviewMapboxNavigationAPI::class)
private fun initNavigation() {
MapboxNavigationApp.setup(NavigationOptions.Builder(this).build())
// initialize location puck
mapView.location.apply {
setLocationProvider(navigationLocationProvider)
this.locationPuck = createDefault2DPuck()
enabled = true
}
val origin = Point.fromLngLat(-122.43539772352648, 37.77440680146262)
val destination = Point.fromLngLat(-122.42409811526268, 37.76556957793795)
mapboxNavigation.requestRoutes(
RouteOptions.builder()
.applyDefaultNavigationOptions()
.coordinatesList(listOf(origin, destination))
.layersList(listOf(mapboxNavigation.getZLevel(), null))
.build(),
object : NavigationRouterCallback {
override fun onCanceled(routeOptions: RouteOptions, routerOrigin: String) {}
override fun onFailure(reasons: List<RouterFailure>, routeOptions: RouteOptions) {}
override fun onRoutesReady(routes: List<NavigationRoute>, routerOrigin: String) {
mapboxNavigation.setNavigationRoutes(routes)
// start simulated user movement
val replayData =
replayRouteMapper.mapDirectionsRouteGeometry(routes.first().directionsRoute)
mapboxNavigation.mapboxReplayer.pushEvents(replayData)
mapboxNavigation.mapboxReplayer.seekTo(replayData[0])
mapboxNavigation.mapboxReplayer.play()
}
}
)
}
}
- Click File > Sync Project with Gradle Files
- Click the play button to build the app and run it on an emulator or device. After the map loads, you will see simulated navigation begin, with the camera following the user's location along the route.
You can experiment with the code to customize the navigation experience. For example, you can change the route's origin and destination points, or add custom logic to handle user location updates.
See the full example for a more complex turn-by-turn navigation experience using the full suite of the SDK's UI components, including speed limit, route shields, maneuver instructions, and voice prompts.
Next Steps
-
Consult our concept guides to learn more about Initializing the SDK, Location Tracking, how to use the UI Components, and more.
-
See the full list of Navigation SDK examples to explore more ways to use the SDK in your app. We recommend cloning the Mapbox Navigation Examples App and running it locally to interact with each example and explore the source code.
-
Explore the reference documentation for detailed information about the SDK's classes, methods, and interfaces.