Skip to main content

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:

  1. Go to your account's tokens page.
  2. Click the Create a token button.
  3. Name your token, for this example we've used InstallTokenAndroid.
  4. Scroll down to the Secret Scope section and check the Downloads:Read scope box.
  5. Click the Create token button at the bottom of the page to create your token.
  6. Enter your password to confirm the creation of your token.
  7. 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.
Protect secret access tokens

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.

~/.gradle/gradle.properties
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.

  1. 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.
  1. Locate the resource folder:
  • In the project explorer, open your resource folder located at app/res/values.
  1. 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.
  1. 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.
app/res/values/mapbox_access_token.xml
<?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
GUIDE
Access token best practices

Learn how to keep access tokens private in mobile apps.

Adding Tokens at Runtime

You can also implement tokens at runtime, but this requires you to have a separate server to store your tokens. This is helpful if you want to rotate your tokens or add additional security by storing your tokens outside of the APK, but is a much more complex method of implementation.

If you do choose to follow this method, we recommend calling MapboxOptions.accessToken = YOUR_PUBLIC_MAPBOX_ACCESS_TOKEN before inflating the MapView, otherwise the app will crash.

Rotating Tokens

For more information on access token rotation, consult the Access Tokens Information page.

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" />
Understanding the POST_NOTIFICATIONS permission

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.

  1. In Android Studio, under Gradle Scripts, open the settings.gradle file.
  2. Add a new maven {...} definition inside dependencyResolutionManagement.repositories.
settings.gradle
 
// Mapbox Maven repository
 
maven {
 
url = uri("https://api.mapbox.com/downloads/v2/releases/maven")
 
authentication {
 
basic(BasicAuthentication)
 
}
 
credentials {
 
// Do not change the username below.
 
// This should always be `mapbox` (not your username).
 
username = "mapbox"
 
// Use the secret token you stored in gradle.properties as the password
 
password = providers.gradleProperty("MAPBOX_DOWNLOADS_TOKEN").get()
 
}
 
}

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.

  1. In Android Studio, open your module-level build.gradle file.

  2. Add the Navigation SDK dependencies under dependencies.

You can add the full SDK with a single dependency by adding the android module:

build.gradle
dependencies {
...
implementation "com.mapbox.navigationcore:android:3.7.0"
...
}

You can also include individual modules based on your app's requirements:

ModuleDescription
com.mapbox.navigationcore:copilotThe Copilot is a component that collects detailed trace files of navigation sessions together with search analytics data.
com.mapbox.navigationcore:ui-mapsThe 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:navigationThe Navigation module is the primary interface for engaging with the Navigation SDK.
com.mapbox.navigationcore:tripdataThe Trip Data component provides convenient API to request maneuver instructions, route shields, speed limit, and trip progress data.
com.mapbox.navigationcore:ui-componentsThe UI components module provides pre-built UI widgets.
com.mapbox.navigationcore:voiceThe Voice component allows users to access Voice API.
build.gradle
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"
...
}
  1. Make sure that your project's minSdk is 21 or higher:
build.gradle
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:

  1. Add the sample code below to your MainActivty.kt file.
MainActivity.kt
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()
}
}
)
}
}
  1. Click File > Sync Project with Gradle Files
  2. 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.

EXAMPLE
Add a complete turn-by-turn experience

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

Method limit
If you've added the Navigation SDK, finished all the installation steps above, and see an Android Studio error saying that you've reached maximum method count, try enabling Multidex following the official Android guides to using multidex and optimizing your code.
Was this page helpful?