メインコンテンツまでスキップ

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 accesses the secret access token you configured in Part 1 to authenticate with the Mapbox Maven repository.

Add the Mapbox Maven repository in the correct location

Make sure you configure the Mapbox maven repository inside dependencyResolutionManagement and not inside pluginManagement.

Step 2: Add Nav SDK dependencies

Next, add the Nav SDK modules to your project to start using the Mapbox Navigation SDK for Android:

  1. In Android Studio, open your module-level build.gradle file.
  2. Add the Navigation SDK dependency under dependencies.
    • This will allow you to access base navigation services, like creating a route.
build.gradle
dependencies {
...
implementation "com.mapbox.navigationcore:android:3.9.2" // Adds core Navigation SDK functionality
...
}
Additional Navigation Services - Limiting dependencies in the SDK

There are other navigation modules you can add to your implementation, based on your app's requirements. See the list below:

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:copilot:3.9.2"
implementation "com.mapbox.navigationcore:ui-maps:3.9.2"
implementation "com.mapbox.navigationcore:voice:3.9.2"
implementation "com.mapbox.navigationcore:tripdata:3.9.2"
implementation "com.mapbox.navigationcore:android:3.9.2"
implementation "com.mapbox.navigationcore:ui-components:3.9.2"
...
}
  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, create a turn-by-turn navigation with simulated user locations.

The code below displays a scaled-down navigation experience with a map, route line, and location puck.

  1. Add the sample code below to your MainActivty.kt file to run the simulation:
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.

Troubleshooting

If your implementation is not working as expected, view the following troubleshooting solutions:

Black screen

If when you run simulator your screen displays black, here are some possible solutions:

  • Make sure both your secret token and public token are both valid and present
    • If you see YOUR_MAPBOX_ACCESS_TOKEN in your code, your map will not render.
  • If you are also seeing this error onmaploaderror: style, message: failed to load style: couldn't connect to server: exception in croneturlrequest: net::err_name_not_resolved, you will need to wipe your simulator data.
    • This error could be caused by your simulator losing access to the internet. To fix this problem, try the following:
      • Make sure you have access to the internet.
      • If you have internet access, next click Tools > Device Manager.
      • Then click options and select Wipe Data.
      • Wait until your simulator loads back up, and then try running the simulator again.
Route does not appear

If your map appears but the route does not appear on the map, here are some possible solutions:

  • If this is the first time running the simulator after setting location permissions, try restarting the simulator and running it again.
  • Make sure you are using a valid secret token.
    • This token must use the Downloads:Read scope.
  • Make sure your token is assigned in your gradle.properties file.
  • Make sure the settings.gradle.kts file inside the credentials struct, the username is mapbox and not your username.
Maximum method count

Try enabling Multidex by following the official Android guides, using multidex and optimizing your code.

My application is crashing on start or won't build
  • Make sure the package line in your MainActivity.kt matches your project name and does not read package com.example.myapplication.
  • Make sure you configure the Mapbox maven repository inside dependencyResolutionManagement and not inside pluginManagement in your settings.gradle.kts file.
General Tips

Make sure your always click Save All and Sync Project with Gradle Files when making changes to your application.

Next Steps

Congratulations! You've gotten your application up and running with the Mapbox Navigation SDK for Android.

What we've covered

  • Created a secret token
  • Added secret and public tokens to your project.
  • Added a maven dependency to install the Mapbox Navigation SDK for Android
  • Learned about how permissions work in Android
  • Ran a minimal example showing turn-by-turn navigation

Learn more

Explore other learning related to Mapbox Navigation SDK for Android:

RELATED
Mapbox Navigation Examples App

Clone the Mapbox Navigation Examples App repository to view examples in action.

EXAMPLE
Display the user’s location

This example demonstrates how to track and display the user's location.

EXAMPLE
Simulate a navigation route

This examples demonstrates how to simulate a navigation route on the map.

この{Type}は役に立ちましたか?