Get started
Review the Google developer documentation to learn how to develop apps for Android Auto. You should also review the functionality checklist to make sure your app meets the Google Play requirements. This guide will help you add Mapbox Navigation to a new or existing app. It will also refer you to other documentation when necessary. If you are looking to use Mapbox Maps in Android Auto without Mapbox Navigation, refer to the Mapbox Android Auto Extension.
Feel free to request changes, or open pull requests.
1. Set up MAPBOX_DOWNLOADS_TOKEN
Refer to the Mapbox Navigation SDK install guide to get permission to download SDKs. If you have already set up a MAPBOX_DOWNLOADS_TOKEN
, you can skip this step.
2. Make sure minSdk
23+
Android Auto is only compatible with phones running Android 6.0 (API level 23) or higher.
android {
defaultConfig {
minSdk 23
...
}
3. Add the dependency
Add the library dependency to your build.gradle
. The library version matches Navigation SDK version, they have the same release cadence. This way, you should not worry about versions compatibility, alight versions of the both SDK's and that would work.
dependencies {
implementation "com.mapbox.navigation:android-auto-components:3.4.0"
}
4. Add your meta-data
and CarAppService
You need to add elements to the application
in your AndroidManifest.xml
. The meta-data
specifies support for Android Auto or Android Automotive. You do not need to add the automotive_app_desc
because it is included by the Mapbox Navigation Android Auto SDK. The CarAppService
has an intent-filter
to specify the category
of your app. If you specify the wrong meta-data
or category
, your app will be rejected by Google Play.
<!-- metadata if your app supports Android Auto -->
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="@xml/automotive_app_desc" />
<!-- metadata if your app supports Android Automotive -->
<meta-data
android:name="com.android.automotive"
android:resource="@xml/automotive_app_desc" />
<service
android:name=".car.MainCarAppService"
android:exported="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:foregroundServiceType="location">
<intent-filter>
<action android:name="androidx.car.app.CarAppService" />
<category android:name="androidx.car.app.category.NAVIGATION" />
</intent-filter>
</service>
class MainCarAppService : CarAppService() {
override fun createHostValidator() = HostValidator.ALLOW_ALL_HOSTS_VALIDATOR
override fun onCreateSession() = MainCarSession()
}
5. Managing state between the car and app
When integrating Android Auto with your application, an issue you are likely to face, is determining when the car or app is in use. Luckily, the car and app have something in common, The Jetpack
Lifecycle Library. To create Lifecycle
aware services, we have introduced MapboxNavigationApp
. This is built on top of the Lifecycle
. It is recommended to set up MapboxNavigation
as explained in Initialize the SDK guide before following the steps outlined below. Also, refer to Android Auto Lifecycle
documentation for questions about Session and Screen Lifecycle
.
6. Implement your Session
The Session
is a LifecycleOwner
and serves as the entry point for Android Auto. This is where you can create experiences that fit your domain and complete the functionality checklist.
- Set up the
MapboxCarMap
- Set up
MapboxNavigationApp
- Prepare the
MapboxScreenManager
- Create an experience for accepting location permissions
- Update the Map style when the configuration changes
- Parse
onNewIntent
for voice activated navigation
The following are working examples. Use them as a guide to create your own experiences.
- Latest
MapboxCarMap
examples are part of the Mapbox Android Auto Extension
The following is an example of what your Session can look like.
class MainCarSession : Session() {
// Create the MapboxCarContext and MapboxCarMap. You can use them to build
// your own customizations.
private val carMapLoader = MapboxCarMapLoader()
private val mapboxCarMap = MapboxCarMap().registerObserver(carMapLoader)
private val mapboxCarContext = MapboxCarContext(lifecycle, mapboxCarMap)
init {
// Attach the car lifecycle to MapboxNavigationApp.
// You do not need to detach because it will interally detach when the lifecycle is detroyed.
// But you will need to unregister any observer that was registered within the car lifecycle.
MapboxNavigationApp.attach(lifecycleOwner = this)
// Prepare a screen graph for the session. If you want to customize
// any screens, use the MapboxScreenManager.
mapboxCarContext.prepareScreens()
// At any point you can customize the MapboxCarOptions available.
mapboxCarContext.customize {
// You need to tell the car notification which app to open when a
// user taps it.
notificationOptions = MapboxCarNotificationOptions.Builder()
.startAppService(MainCarAppService::class.java)
.build()
}
lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onCreate(owner: LifecycleOwner) {
// Ensure MapboxNavigationApp has an access token and a application context.
// This can also be done in Application.onCreate. Use the isSetup condition in case the
// options have been set by a separate lifecycle event, like an Activity onCreate.
if (!MapboxNavigationApp.isSetup()) {
MapboxNavigationApp.setup(
NavigationOptions.Builder(carContext)
.accessToken(Utils.getMapboxAccessToken(carContext))
.build()
)
}
// Once a CarContext is available, pass it to the MapboxCarMap.
mapboxCarMap.setup(carContext, MapboxInitOptions(context = carContext))
}
override fun onDestroy(owner: LifecycleOwner) {
// The car session is destroyed you so should remove any observers. This
// will ensure every MapboxCarMapObserver.onDetached is called.
mapboxCarMap.clearObservers()
}
})
}
override fun onCreateScreen(intent: Intent): Screen {
// You can control the MapboxScreenManager from a mobile device, in which case you will
// want to get the first screen from there. Most of the MapboxScreens require location
// permission and the default NEEDS_LOCATION_PERMISSION will assume location permissions
// are requested from a mobile app.
val firstScreenKey = if (PermissionsManager.areLocationPermissionsGranted(carContext)) {
MapboxScreenManager.current()?.key ?: MapboxScreen.FREE_DRIVE
} else {
MapboxScreen.NEEDS_LOCATION_PERMISSION
}
// Use the MapboxScreenManager to keep track of the screen stack.
return mapboxCarContext.mapboxScreenManager.createScreen(firstScreenKey)
}
override fun onCarConfigurationChanged(newConfiguration: Configuration) {
// Notify a map loader of the dark mode style change
carMapLoader.updateMapStyle(carContext.isDarkMode)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
// Use the GeoDeeplinkNavigateAction or GeoDeeplinkParser to parse
// incomming intents and change the navigation screen
GeoDeeplinkNavigateAction(mapboxCarContext).onNewIntent(intent)
}
}
7. Customize your experience
To provide a default experience for Android Auto, we have prepared default Screens with default experiences. See the screenshot available in the following sections, that should give you an idea for what is included inside this library. You are free to use what is available. If you are unable to build your custom experience, make requests so we can build an SDK that helps you build with Mapbox!