Skip to content

1.0 Navigation SDK Migration Guide

Erin Quinn edited this page Feb 18, 2021 · 7 revisions

“The Mapbox Navigation SDK” is actually comprised of two SDKs that can be used to integrate navigation into your Android project:

  • The Navigation SDK. This is where core logic lives for generating routes, tracking route progress, delivering turn-by-turn instructions, and other actions related to Directions API information.
  • The Navigation UI SDK. Built on top of the Navigation SDK, the Navigation UI SDK consumes data from the Navigation SDK and arranges it in default UI components that have various customizable options.

Read the 1.0 Navigation SDK’s entire documentation at https://docs.mapbox.com/android/navigation/overview

Pricing changes

Applications built with v1.0.0+ are billed based only on monthly active users, specifically "Navigation SDKs" MAUs which are described in more detail in the Navigation SDK for Android pricing guide. Navigation SDK MAUs include Directions API, Vector Tiles API, and Raster Tiles API requests with no upfront commitments or annual contracts. A single user is billed as one MAU across app upgrades as long as the app is not deleted. Deleting and re-installing an app that uses the Navigation SDK would result in an additional MAU. This happens because the SDK does not store personally identifying information. To see the number of Navigation SDKs MAUs included in the free tier and the cost per Navigation SDKs MAU beyond the free tier, see the Navigation SDKs section of our pricing page.

About the 1.0 Navigation SDK:

The 1.0 release of the SDK debuts code for a vastly more straightforward way of building a navigation experience. The SDK brings completely new features, including:

  • a higher accuracy location engine that functions even in low GPS quality scenarios such as tunnels or overpasses.

  • free drive capabilities. Also known as passive navigation, drivers can now navigate in a mode without a destination entered.

  • a comprehensive modular and extensible architecture exposing stable and performant APIs that are hard to misuse, allowing your developers options to integrate custom analytics or a custom router. As long as these modules follow the API definitions, they can be customized and easily integrated.

Kotlin:

The 1.0 Navigation SDK is written 100% in Kotlin. This is a change from how the pre-1.0 versions were written in Java.

Setting up the 1.0 Navigation SDK

Please see https://docs.mapbox.com/android/navigation/overview/#installation for the most up-to-date instructions on installing the 1.0 Navigation SDK.

Minimum Android SDK:

The Mapbox Android Navigation team has decided to bump the minimum Android SDK version to 21 for the 1.0 SDK. Please make sure that your project’s minSdkVersion is set to 21 or higher in your application-level build.gradle file.

android {

    defaultConfig {
        …	
        minSdkVersion 21
        …
        …
    }
}

NavigationOptions

NavigationOptions is the 1.0 version of the pre-1.0 MapboxNavigationOptions class. NavigationOptions has a Builder class and you can use the Builder class to explore what methods are available for setting specific options such as your preferred units to use for distance and time.

val navigationOptions = NavigationOptions.Builder()
.distanceFormatter(MapboxDistanceFormatter.builder()
.withRoundingIncrement(Rounding.INCREMENT_FIFTY)
.withUnitType(VoiceUnit.METRIC)
.build(this))
.timeFormatType(TWELVE_HOURS)
.build()

Once created, the NavigationOptions object should be used as a method parameter when initializing the MapboxNavigation class.

More information about the NavigationOptions class can be found at https://docs.mapbox.com/android/navigation/overview/#set-navigationoptions.

MapboxNavigation:

Creating a MapboxNavigation object is the first step in interacting with and customizing a navigation session. It's used to request routes, register various Navigation SDK observers, and make other navigation-related decisions. It needs a context object as well as a valid Mapbox access token.

Create and use only one instance of this class in your project.

val navigation = MapboxNavigation.defaultNavigationOptions(context, MAPBOX_ACCESS_TOKEN)

Alternatively, use the MapboxNavigation's constructor if you'd like to set the various options yourself:

val mapboxNavigation = MapboxNavigation(
applicationContext,
mapboxNavigationOptions,
LocationEngineProvider.getBestLocationEngine(this)
)

Don’t forget to call mapboxNavigation.onDestroy() in the lifecycle onDestroy() part of your Android project.

override fun onDestroy() {
        super.onDestroy()
        mapboxNavigation.onDestroy()
}

More information about the MapboxNavigation class can be found at https://docs.mapbox.com/android/navigation/overview/#create-a-mapboxnavigation-object

ROUTING

Requesting a route:

After you’ve created a mapboxNavigation object, you can use its requestRoutes() method. The method requires a built RouteOptions object. The RouteOptions class has convenient methods for setting the various route parameters that can be found at https://docs.mapbox.com/api/navigation/#directions. Despite the many builder methods, only accessToken, origin, and destination are required to build a valid route request.

mapboxNavigation.requestRoutes(
	RouteOptions.builder()
	    .accessToken(MAPBOX_TOKEN)
	    .coordinates(mutableListOf(originPoint, destinationPoint))
	    .geometries(RouteUrl.GEOMETRY_POLYLINE6)
	    .profile(RouteUrl.PROFILE_DRIVING)
	    .build()
)

More information at https://docs.mapbox.com/android/navigation/overview/route-generation/#request-a-route

Route status:

The mapboxNavigation.requestRoutes() method’s only required parameter is the built RouteOptions object. An optional second parameter is a RoutesRequestCallback interface object. The 1.0 Navigation SDK’s RoutesRequestCallback interface provides methods that inform you about the route request status.

val routesReqCallback = object : RoutesRequestCallback {
    override fun onRoutesReady(routes: List<DirectionsRoute>) {

    }

    override fun onRoutesRequestFailure(throwable: Throwable, routeOptions: RouteOptions) {


    }

    override fun onRoutesRequestCanceled(routeOptions: RouteOptions) {
        
    }
}

You’ll typically want navigationMapboxMap to draw the first route returned inside of onRoutesReady():

private val routesReqCallback = object : RoutesRequestCallback {
    override fun onRoutesReady(routes: List<DirectionsRoute>) {
        if (routes.isNotEmpty()) {
            navigationMapboxMap?.drawRoute(routes[0])
}
    }

    override fun onRoutesRequestFailure(throwable: Throwable, routeOptions: RouteOptions) {
        
    }

    override fun onRoutesRequestCanceled(routeOptions: RouteOptions) {
        
    }
}

More information at https://docs.mapbox.com/android/navigation/overview/route-generation/#route-request-status

Changed routes:

Use the 1.0 Navigation SDK’s RouteObserver interface if you want to know when the routes list has changed. Registering a RouteObserver interface object via mapboxNavigation.registerRouteObserver(routeObserver) is one way to do it. Alternatively, you can implement the interface, register the interface with mapboxNavigation.registerRouteObserver(this), and override the interface’s single method.

private val routeObserver = object : RouteObserver {
    override fun onRoutesChanged(routes: List<DirectionsRoute>) {
    	navigationMapRoute?.addRoutes(routes)
    }
}

More information at https://docs.mapbox.com/android/navigation/overview/route-generation/#changed-routes

Listening to route progress:

ProgressChangeListener is the pre-1.0 interface callback for receiving information about where the device is along the directions route in turn-by-turn navigation mode.

RouteProgressObserver is the 1.0 Navigation SDK’s equivalent interface. This new interface only has one method, which is onRouteProgressChanged(). The interface still returns a RouteProgress object.

private val routeProgressObserver = object : RouteProgressObserver {
    override fun onRouteProgressChanged(routeProgress: RouteProgress) {
       
    }
}

Alternatively, you can implement the interface, register the interface with mapboxNavigation.registerRouteProgressObserver(this), and override the interface’s method.

Don’t forget to unregister the interface!

override fun onStop() {
    super.onStop()
    mapView.onStop()
    mapboxNavigation.unregisterRouteProgressObserver(routeProgressObserver)
}

More information at https://docs.mapbox.com/android/navigation/overview/route-progress/

Optional faster route

FasterRouteObserver is the 1.0 Nav SDK’s way to listen to the retrieval of a faster DirectionsRoute.

The observer object:

private val fasterRouteObserver = object : FasterRouteObserver {
    override fun restartAfterMillis() = FasterRouteObserver.DEFAULT_INTERVAL_MILLIS
    
    override fun onFasterRoute(
        currentRoute: DirectionsRoute,
        alternatives: List<DirectionsRoute>,
        isAlternativeFaster: Boolean
    ) {
        
        
    }
}

Attach the observer interface:

mapboxNavigation.attachFasterRouteObserver(fasterRouteObserver)

Don’t forget to detach the observer interface!

override fun onStop() {
    super.onStop()
    mapView.onStop()
    mapboxNavigation.detachFasterRouteObserver()
}

More information at https://docs.mapbox.com/android/navigation/overview/faster-route

LOCATION

1.0 introduces a new interface listener to use for receiving device location updates. The LocationObserver’s two methods will fire whenever the device changes location. If you’re using the Navigation UI SDK, you don’t have to use the LocationObserver interface for a standard 1.0 Navigation SDK setup. The Navigation UI SDK automatically handles displaying the device location puck on the map. The Navigation SDK doesn't include any UI pieces at all, except for the sticky foreground notification.

The LocationObserver interface is optional and is available in case you want to track device location yourself and do anything with the returned Location object’s coordinates or altitude values.

private val locationObserver = object : LocationObserver {
    override fun onRawLocationChanged(rawLocation: Location) {
                    
    }

    override fun onEnhancedLocationChanged(
        enhancedLocation: Location,
        keyPoints: List<Location>
    ) {

        
    }
}

Register the observer with the MapboxNavigation object:

mapboxNavigation.registerLocationObserver(locationObserver)

Don’t forget to unregister the interface!

override fun onStop() {
    super.onStop()
    mapView.onStop()
    mapboxNavigation.unregisterLocationObserver(locationObserver)
}

If you use the LocationObserver interface, be sure to also pass false through the LocationComponent’s useDefaultLocationEngine() method so that you can eventually pass the onEnhancedLocationChanged() callback’s Location object to the LocationComponent. Once you pass the Location object, the Navigation SDK will use the LocationComponent to move the device location puck to the appropriate place on the map and make other adjustments.

mapboxMap.setStyle(Style.MAPBOX_STREETS) { style ->
    locationComponent = mapboxMap.locationComponent.apply {
        activateLocationComponent(
LocationComponentActivationOptions.builder(this, style)
            .useDefaultLocationEngine(false)
            .build()
        )
        cameraMode = CameraMode.TRACKING
        isLocationComponentEnabled = true
    }
}

Passing the LocationComponent the Location object returned by LocationObserver:

private val locationObserver = object : LocationObserver {
    override fun onRawLocationChanged(rawLocation: Location) {
    }

   override fun onEnhancedLocationChanged(
        enhancedLocation: Location,
        keyPoints: List<Location>
    ) {
		locationComponent?.forceLocationUpdate(rawLocation)
    }
}

More information at https://docs.mapbox.com/android/navigation/overview/device-location

About the 1.0 Navigation UI SDK

The 1.0 UI SDK release as compared to legacy offers all the features but with a much finer control and granularity. This version mainly serves as a port of the legacy UI SDK implementation to use the 1.0 version of the Navigation Core SDK and its features. The 1.0 UI SDK also removes redundant methods & APIs while exposing new ones instead. The SDK also brings new features, including:

  • two different ways of providing feedback during a trip session, thereby helping Mapbox provide better route quality, turn-by-turn experiences, traffic congestion, etc.

  • allowing developers to deemphasize portions of the route line behind the puck, thereby reflecting route progress state.

  • providing UI components that visualize a single building footprint or extrusion. Great to use for marking the final destination in an improved arrival experience.

Namespace changes

The SDK introduces namespace changes for all the files. Make sure to change your import lines in your project’s files as well as any references to Navigation UI SDK widgets in your xml files.

Internal package

The 1.0 Navigation UI SDK moves some public class files to an internal package. As the name suggests, these classes are meant to be only used internally. You should not use any of these classes’ public methods as these files are subject to silent changes in the future without breaking Semver.

Setting up the 1.0 Navigation UI SDK

Please see below for the most up-to-date instructions on installing the 1.0 Navigation UI SDK.

Minimum Android SDK

The Mapbox Android Navigation team has decided to bump the minimum Android SDK version to 19 for the 1.0 UI SDK. Please make sure that your project’s minSdkVersion is set to 19 or higher in your application-level build.gradle file.

android {

    defaultConfig {
        …	
        minSdkVersion 19
        …
        …
    }
}

The Navigation SDK uses Java 8 features. To enable Java 8 in your project, add the following compileOptions

android {
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

Drop-In UI

Unlike the legacy UI SDK, the 1.0 Navigation UI SDK removes the support of NavigationLauncher and MapboxNavigtionActivity. NavigationLauncher made it easy for the developer to display turn-by-turn navigation UI using the route already retrieved from the core Mapbox Navigation SDK for Android. NavigationLauncher exposed Builder options to allow developers to configure route and navigation options. These options would then be inflated in the MapboxNavigationActivity. However, this approach imposed limitations in the sense that customizing properties and features on-the-fly was very difficult to achieve. Exposure to Activity didn’t allow for creating and registering custom observers and also runtime styling without affecting the lifecycle of the Activity.

Instead, if you want the 1.0 Navigation UI SDK to display turn-by-turn UI for you, we encourage you to make use of NavigationView. The NavigationView should be familiar from the pre-1.0.0 versions of the Navigation UI SDK and it gives you more control over styling the UI components. It also provides various callbacks to deliver relevant information. Please see the NavigationViewActivity and NavigationViewFragmentActivity examples for Activity and Fragment based implementations.

Routes

If you are using the NavigationView component of the UI SDK, you would need to fetch the route using the Core SDK first and then supply it using NavigationViewOptions. Refer to https://github.com/mapbox/mapbox-navigation-android/wiki/1.0-Navigation-SDK-Migration-Guide#routing for information on fetching route.

Once you are in active navigation mode and you reroute for any reasons, NavigationView would handle the reroute event. If you are not using the NavigationView, you would have to observe the reroute event and make appropriate changes to your UI, like calling NavigationMapboxMap#drawRoutes.

Styling

The 1.0 Navigation UI SDK exposes the ability for developers to style the UI widgets regardless of whether the widgets are being used independently or within the NavigationView. These UI widgets include:

  • InstructionView
  • SummaryBottomSheet
  • RecenterButton
  • WayNameView
  • MapRouteLine
  • NavigationMapRoute

For example, if you want to style the RecenterButton:

In your project’s values/styles.xml file:

<style name="CustomRecenterButton">
    <!-- Recenter button background color -->
    <item name="recenterButtonPrimaryColor">@color/navigation_primary_background</item>
    <!-- Recenter button text color -->
    <item name="recenterButtonSecondaryColor">@color/navigation_accent</item>
</style>

To apply the style, add the RecenterButton to your project’s xml file where you are using the Navigation UI SDK’s RecenterButton.

<com.mapbox.navigation.ui.RecenterButton
    android:id="@+id/recenterBtn"
    style="@style/CustomRecenterButton"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" />

Look at the CustomUIComponentStyleActivity example in the Navigation UI SDK’s repository for more details on custom styling of components.

Voice Instructions:

1.0 removes the support of VoiceInstructionMilestone and MilestoneEventListener. Now it exposes a VoiceInstructionObserver that triggers onNewVoiceInstructions() every time a new voice instruction is available.

Inside your Activity or Fragment:

private val voiceInstructionsObserver = object : VoiceInstructionsObserver {
    override fun onNewVoiceInstructions(voiceInstructions: VoiceInstructions) {
        // play voice instructions
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    mapboxNavigation = MapboxNavigation(
        applicationContext,
        mapboxNavigationOptions,
        locationEngine = getLocationEngine()
    ).apply {
        registerVoiceInstructionsObserver(voiceInstructionsObserver)
    }
}

override fun onDestroy() {
    super.onDestroy()
    mapboxNavigation?.apply {
        unregisterVoiceInstructionsObserver(voiceInstructionsObserver)
    }
    mapboxNavigation.onDestroy()
}

Similarly, SpeechAnnouncement has been removed and replaced by VoiceInstructions.

Banner Instructions:

1.0 exposes a BannerInstructionsObserver that triggers onNewBannerInstructions() every time a new banner instruction is available. It acts as the data source containing maneuver information that’s helpful in turn-by-turn navigation.

Inside your Activity or Fragment:

private val bannerInstructionObserver = object : BannerInstructionsObserver {
        override fun onNewBannerInstructions(bannerInstructions: BannerInstructions) {
            // update banner
        }
    }

override fun onCreate(savedInstanceState: Bundle?) {
    mapboxNavigation = MapboxNavigation(
        applicationContext,
        mapboxNavigationOptions,
        locationEngine = getLocationEngine()
    ).apply {
        registerBannerInstructionsObserver(bannerInstructionObserver)
    }
}

override fun onDestroy() {
    super.onDestroy()
    mapboxNavigation?.apply {
        unregisterBannerInstructionsObserver(bannerInstructionObserver)
    }
    mapboxNavigation.onDestroy()
}

Feedback:

1.0 enables developers to allow their users to send feedback in two different ways. A user can now send feedback detailing the issue during turn-by-turn navigation.

To allow your user just to be able to report problem:

FeedbackBottomSheet.newInstance(
    object : FeedbackBottomSheetListener {
        override fun onFeedbackSelected(feedbackItem: FeedbackItem?) {
            MapboxNavigation.postUserFeedback(...)
        }

        override fun onFeedbackDismissed() {
            // handle events when feedback is dismissed
        }
    },
    FeedbackBottomSheet.FEEDBACK_MAIN_FLOW,
    0L // FeedbackBottomSheet duration in Long
).show(it, FeedbackBottomSheet.TAG)

To allow your user to go one step deeper to submit more details about the problem:

FeedbackBottomSheet.newInstance(
    object : FeedbackBottomSheetListener {
        override fun onFeedbackSelected(feedbackItem: FeedbackItem?) {
            MapboxNavigation.postUserFeedback(...)
        }

        override fun onFeedbackDismissed() {
            // handle events when feedback is dismissed
        }
    },
    FeedbackBottomSheet.FEEDBACK_DETAIL_FLOW,
    0L // FeedbackBottomSheet duration in Long
).show(it, FeedbackBottomSheet.TAG)

For further information on how to use Navigation UI SDK 1.0, you can refer to these examples.

Next steps

Again, not all of the Navigation SDK’s new features are covered in this migration guide. This guide makes assumptions about what parts of the Navigation SDK a simple and barebones navigation project will use.

Read the Navigation SDK’s complete documentation at http://docs.mapbox.com/android/navigation/overview.

Questions?

If you’ve got any questions, please reach out to the Mapbox team via https://github.com/mapbox/mapbox-navigation-android/issues/new.