-
Notifications
You must be signed in to change notification settings - Fork 319
1.0 Navigation SDK Migration Guide
“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
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.
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.
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.
- https://kotlinlang.org/docs/reference/java-interop.html#calling-java-code-from-kotlin and https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html have helpful information on Java and Kotlin interoperability.
Please see https://docs.mapbox.com/android/navigation/overview/#installation for the most up-to-date instructions on installing the 1.0
Navigation 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
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.
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
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
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
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
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/
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
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
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.
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.
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.
Please see below for the most up-to-date instructions on installing the 1.0
Navigation UI 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
}
}
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.
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
.
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.
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
.
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()
}
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.
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.
If you’ve got any questions, please reach out to the Mapbox team via https://github.com/mapbox/mapbox-navigation-android/issues/new.