migrating-navsdk-7x-to-8x-android
About migrating-navsdk-7x-to-8x-android
A migration skill for Android developers moving Navigation SDK from 7.x to 8.0. It organizes toolchain, dependency, breaking-change, and deprecation checks into phases, and supports audit-only work without code edits.
Key features
- 01Pre-migration environment and code inventory
- 02Phased toolchain and dependency upgrades
- 03Identification of required API changes
- 04Deprecation list with replacement guidance
- 05Audit-only findings without edits
Use cases
- 01Upgrade an Android app from NavSDK 7.x to 8.0
- 02Check AGP, Gradle, and JDK requirements before upgrading
- 03Find API changes that can break builds or behavior
- 04Assess migration work without modifying code
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ googlemaps/ agent-skills --skill migrating-navsdk-7x-to-8x-androidAfter installing, type/migrating-navsdk-7x-to-8x-androidin Claude Code to confirm it loaded.
Bundled filesreferences/toolchain_bump.md
Details
From the project READMEMigrating Navigation SDK for Android 7.x to 8.0
Read this first: what does not change
This is a version bump of the same SDK. Don't rename packages, swap artifacts, or change how the navigator is initialized.
- Package namespace stays
com.google.android.libraries.navigation.*. Do not rewrite imports. - Artifact stays
com.google.android.libraries.navigation:navigation. Only the version changes. - Initialization is unchanged. Keep calling
NavigationApi.getNavigator(...)exactly as before. Navigator.RouteStatusis still a Javaenum. Do not convert it tointconstants.
Workflow
Work in this order. Nothing compiles on 8.0 until the toolchain is right, and fixing call sites against a build that won't configure wastes a cycle. Hard breaks come before deprecations because removed symbols cannot compile, while deprecated ones only warn. Phase 4 is a scheduling decision for the developer, not a mandate.
Phase 0: Preflight
Record these before you change anything; later phases branch on them:
- Current NavSDK version
(
com.google.android.libraries.navigation:navigation:<version>). This skill covers 7.x to 8.0 only. If the app is on 6.x or older, first upgrade to the latest 7.x using the release notes, get a green build, then continue here. - Build DSL (Groovy
build.gradlevs. Kotlinbuild.gradle.kts), AGP and Gradle versions, and the JDK running Gradle. - Source languages (Java, Kotlin, or both).
- Whether layout XML references NavSDK fragments, and whether the app uses
Android Auto (
androidx.car.app). - The user's goal: full migration, just "make it build", or an audit only. For an audit, report the Phase 1-4 findings and make no edits.
Inventory the affected symbols in one pass. The result is the work list for the
rest of the migration: each hit maps to a Phase 1-4 item below, and an audit
reports these hits grouped by phase. Search layout XML too, because fragment
class names in XML only fail at inflation time. Kotlin code usually infers the
future type (val pending = navigator.setDestination(...)), so
ListenableResultFuture alone misses it; setOnResultListener catches those.
Search Java, Kotlin, XML, Gradle, and ProGuard files for the symbols below. Use your environment's code search if there's no shell; with a shell, this command does it:
grep -rnE "showTrafficLights|showStopSigns|onGpsAvailabilityUpdate|ListenableResultFuture|setOnResultListener|SupportNavigationFragment|setAudioGuidance\(|simulateLocationsAlongNewRoute|MAP_TYPE_TERRAIN|RouteStatus|getNavigator|NavigationTransactionRecorder|FollowMyLocationOptions|header[A-Za-z]*(TypefacePath|TextSize)|kotlin-reflect|kotlin\.reflect|bumptech\.glide|androidx\.car\.app" \
--include=*.java --include=*.kt --include=*.xml --include=*.gradle --include=*.kts --include=*.pro .
Phase 1: Toolchain
8.0's AAR metadata declares minAndroidGradlePluginVersion=9.0.1. On AGP 8.x,
Gradle refuses to configure the build: you get no deprecation warning, just
a hard failure. Fix this first.
If the project is already on AGP >= 9.0.1 and compileSdk 37, Phase 1 is a verification step only: confirm the Gradle wrapper satisfies that AGP version and the JDK is 17/21, then move on. Don't downgrade a newer AGP to 9.0.1.
NavSDK 7.x builds fine on AGP 9.0.1 / Gradle 9.1.0 / compileSdk 37 (verified with the published 7.9.0 sample apps). Bump the toolchain while still on 7.x, get a green debug and release build, then change the NavSDK version. That way every later failure is attributable to NavSDK, not AGP.
- Android Gradle plugin: 8.13.2 to 9.0.1. Hard minimum (AAR metadata).
- Gradle: 8.13 to 9.1.0 (for AGP 9.0.1). Newer AGP 9.x needs newer Gradle (e.g. AGP 9.2.0 to Gradle 9.4.1); follow the AGP error message.
compileSdk/targetSdk: 36 to 37. SDK targets 37.- Kotlin: 2.3.0 to 2.3.0. Unchanged.
desugar_jdk_libs_nio: 2.0.x to 2.1.5. Enforced via AAR metadata.com.google.gms:google-services: 4.4.x to 4.5.0. Only if used (AGP 9 removedapplicationVariants).
AGP 9.0.1 prints "This Android Gradle plugin (9.0.1) was tested up to compile
SDK version 36.1" for compileSdk 37. That warning is expected and harmless; to
silence it add android.suppressUnsupportedCompileSdk=37.0 to
gradle.properties (or use a newer AGP 9.x).
Caution
Do not tell developers they need JDK 25. JDK 25 is the internal toolchain used to build NavSDK itself. For a host app on AGP 9, JDK 17 is the minimum Gradle runtime and JDK 21 LTS is recommended.
AGP 9 itself introduces behavior changes that surface as build failures with no
obvious NavSDK link (e.g. package= in the manifest, kotlinOptions,
dexOptions). Read references/toolchain_bump.md
for the symptom-to-fix list. Link the official
AGP 9.0 release notes
rather than restating them. For Kotlin Multiplatform modules that combine
org.jetbrains.kotlin.multiplatform with an Android plugin, follow JetBrains'
AGP 9 migration guidance
(the kotlin-tooling-agp9-migration skill) for the module restructuring, and
still apply the NavSDK floors above.
targetSdk 37 has a Play Console consequence, not a code change: apps that
use NavSDK must complete the Location Purpose Declaration in Google Play
Console. Select Navigation to justify persistent precise location
(ACCESS_FINE_LOCATION) during guidance, and also declare any non-navigation
uses. Tell the user; you cannot do it from code. See the
Play Console location declaration guide.
Phase 2: Dependencies
8.0 stops pulling in several transitive dependencies. The size reduction depends on the app: up to ~4.8 MB for apps that did not already strip them, and much less for apps already shrinking with R8 (for example, full mode):
org.jetbrains.kotlin:kotlin-reflectcom.github.bumptech.glide:glideandcom.github.bumptech.glide:okhttp3-integration
Add one back only if the app's own code references it: kotlin.reflect.*
APIs beyond ::class / KClass basics, or com.bumptech.glide.* imports. A
blanket re-add undoes the size win NavSDK just shipped. A "class not found" for
these packages after the bump is the signal.
Conversely, if the app explicitly declares kotlin-reflect or Glide (often
copied in years ago to mirror NavSDK's transitive set) but has no
kotlin.reflect.* / com.bumptech.glide.* usage in its own code or ProGuard
rules, remove the declaration (and any matching annotationProcessor / kapt /
ksp entries) to realize the size win.
Android Auto: 8.0 no longer bundles ProGuard keep rules for
androidx.car.app. If the app uses the Android Auto projected mode, upgrade
androidx.car.app:app and androidx.car.app:app-projected to 1.3.0 or
higher so their own consumer rules apply. Otherwise release (R8) builds can
strip required classes while debug builds still work.
Other library versions NavSDK bumped (AndroidX lifecycle 2.10.0, material 1.14.0, datastore 1.2.1, window 1.5.1, transport 4.1.1, etc.) resolve automatically through Gradle. Act only if the app pins an older version and dependency resolution fails.
Phase 3: Hard breaks (must fix to compile or behave correctly)
DisplayOptions.showTrafficLights(...),showStopSigns(...): Removed. Delete the calls. Traffic lights and stop signs are now always shown during navigation in countries where this data is available.RoadSnappedLocationProvider.GpsAvailabilityEnhancedLocationListener.onGpsAvailabilityUpdate(boolean): Removed. Delete the override; move logic toonGpsAvailabilityChange(GpsAvailabilityChangeEvent). A leftover@Overridefails compilation.Navigator.RouteStatus.ROUTING_TIMEOUT: New enum constant: routing backend timed out. Add a branch wherever the app handles every status (see below).GoogleMap.MAP_TYPE_TERRAINduring navigation: No longer supported. Compiles fine; at runtime the map falls back toMAP_TYPE_NORMALuntil navigation ends. Remove terrain options from in-navigation UI so users aren't offered a mode that silently doesn't apply.StylingOptionsParcelablemembers (CREATOR,writeToParcel): Internal, not part of the public API. Don't parcelStylingOptions(e.g. viaBundle/Intentextras). Rebuild it from its builder methods where it's needed.NavigationApi.ErrorCode.NETWORK_ERRORfromgetNavigator(Application, ...): Behavior change: can now fire. In 7.x it was never reported. In 8.0, when the terms check fails with a network/timeout error and there is noActivity(theApplicationoverload),onErrorreceivesNETWORK_ERRORwhere it used to receiveTERMS_NOT_ACCEPTED. IfonErrorhas noNETWORK_ERRORbranch, add one that retriesgetNavigator(with backoff) instead of re-prompting for terms or treating it as fatal. Keep any existingNETWORK_ERRORhandling.
ROUTING_TIMEOUT and exhaustiveness. The constant is additive, but it
breaks code that must be exhaustive:
- A Kotlin
when (status)used as an expression fails to compile until it coversROUTING_TIMEOUTor has anelse. - A Java
switchexpression (->form that yields a value) over the enum is a compile error too. - A plain Java
switchstatement compiles but silently skips the new status. Add a case so timeouts get user-visible handling (typically "retry").
val message = when (routeStatus) {
Navigator.RouteStatus.OK -> null
Navigator.RouteStatus.ROUTING_TIMEOUT -> "Route calculation timed out. Try again."
Navigator.RouteStatus.NETWORK_ERROR -> "Network error. Check your connection."
// ...existing branches...
else -> "Could not calculate a route ($routeStatus)."
}
Phase 4: Deprecations (compile with warnings in 8.0; fix now or schedule)
Present these to the user as a choice. Don't silently rewrite every call site
unless they asked for a full migration. For each one, report where it's used and
when it's removed. If the user asked for a full migration, or you are running
non-interactively, migrate every deprecation that has a replacement and list
the ones without a replacement (StylingOptions typeface/text-size, and
FollowMyLocationOptions when the app needs its custom options) as deferred.
ListenableResultFuture<RouteStatus>returned byNavigator.setDestination(s)(...): replace with overloads taking a trailingRouteDescriptionLoadCallbackand returningvoid. Removal: 9.0.Simulator.simulateLocationsAlongNewRoute(...)returningListenableResultFuture: replace with overloads taking a trailingRouteDescriptionLoadCallback. Removal: 9.0.SupportNavigationFragment: replace withNavigationFragment(same package, same methods,newInstance()/newInstance(GoogleMapOptions)). Removal: 9.0.NavigationTransactionRecorder.pickup(Waypoint, List)/dropoff(Waypoint, List): replace withpickup(List)/dropoff(List). Removal: 9.0.Navigator.setAudioGuidance(@AudioGuidance int): replace withsetAudioGuidanceSettings(AudioGuidanceSettings). Removal: ~1 year after 8.0.StylingOptionstypeface-path and text-size methods (header*TypefacePath,header*TextSizeand getters): no replacement; color options remain. Removal: Not announced.GoogleMap.followMyLocation(int, FollowMyLocationOptions)and theFollowMyLocationOptionsclass (com.google.android.gms.maps.model): no direct replacement. If the app doesn't need the custom options (e.g. zoom level), callfollowMyLocation(int)with the same perspective; that overload is not deprecated. Otherwise keep the call and report it as deferred. Removal: a future release (not yet announced).
ListenableResultFuture to RouteDescriptionLoadCallback
RouteDescriptionLoadCallback is the top-level interface
com.google.android.libraries.navigation.RouteDescriptionLoadCallback with a
single method, onRouteDescription(RouteDescription), invoked on the UI thread.
RouteDescription.getRouteStatus() returns the enum
Navigator.RouteStatus.
// Before (deprecated in 8.0)
ListenableResultFuture<Navigator.RouteStatus> future = navigator.setDestination(waypoint);
future.setOnResultListener(status -> {
if (status == Navigator.RouteStatus.OK) {
navigator.startGuidance();
}
});
// After
navigator.setDestination(
waypoint,
routeDescription -> {
if (routeDescription.getRouteStatus() == Navigator.RouteStatus.OK) {
navigator.startGuidance();
}
});
navigator.setDestination(waypoint) { routeDescription ->
if (routeDescription.routeStatus == Navigator.RouteStatus.OK) {
navigator.startGuidance()
}
}
Each setDestination / setDestinations overload (with RoutingOptions,
DisplayOptions, CustomRoutesOptions) has a callback twin with the same
leading parameters.
SupportNavigationFragment to NavigationFragment
Replace the class in both code and layout XML, covering both the
android:name="..." and class="..." attributes on <fragment> /
FragmentContainerView. A code-only replacement compiles cleanly and then
crashes at inflation, or keeps the deprecated class alive in XML.
<fragment
android:id="@+id/navigation_fragment"
android:name="com.google.android.libraries.navigation.NavigationFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
NavigationFragment is an AndroidX Fragment, like
SupportNavigationFragment, so supportFragmentManager usage is unchanged.
Update every reference, not just imports: field/property types, casts such as
(SupportNavigationFragment) getSupportFragmentManager().findFragmentById(...),
instanceof / Kotlin is checks, SupportNavigationFragment() constructor
calls, SupportNavigationFragment.newInstance(...) calls, and KDoc/Javadoc
[SupportNavigationFragment] links. See
Update to NavigationFragment.
setAudioGuidance(int) to setAudioGuidanceSettings(...)
The defaults are inverted. The old flag bitmask was additive from zero, but
AudioGuidanceSettings.builder() starts with vibration on,
GuidanceMode.VOICE_ALERTS_AND_GUIDANCE, Bluetooth audio on, and
VolumeLevel.NORMAL. Explicitly turn off anything the old bitmask omitted.
Map each Navigator.AudioGuidance flag to an AudioGuidanceSettings.Builder
call:
SILENT:setGuidanceMode(GuidanceMode.SILENT)VOICE_ALERTS_ONLY:setGuidanceMode(GuidanceMode.VOICE_ALERTS_ONLY)VOICE_ALERTS_AND_GUIDANCE:setGuidanceMode(GuidanceMode.VOICE_ALERTS_AND_GUIDANCE)VIBRATIONset / absent:setVibrationEnabled(true)/setVibrationEnabled(false)BLUETOOTH_AUDIOset / absent:setBluetoothAudioEnabled(true)/setBluetoothAudioEnabled(false)
// Before: navigator.setAudioGuidance(
// Navigator.AudioGuidance.VOICE_ALERTS_AND_GUIDANCE | Navigator.AudioGuidance.BLUETOOTH_AUDIO);
navigator.setAudioGuidanceSettings(
AudioGuidanceSettings.builder()
.setGuidanceMode(AudioGuidanceSettings.GuidanceMode.VOICE_ALERTS_AND_GUIDANCE)
.setBluetoothAudioEnabled(true)
.setVibrationEnabled(false) // VIBRATION was not in the old bitmask
.build());
Phase 5: Verify and report
- Build both debug and release variants. R8-only failures (Android Auto keep rules, prohibited consumer keep rules under AGP 9) appear only in release.
- Surface deprecation warnings: Kotlin prints
w:lines by default; for Java addoptions.compilerArgs += ["-Xlint:deprecation"]totasks.withType(JavaCompile)(or read the per-file "uses or overrides a deprecated API" note). Re-run the Phase 0 grep. Removed symbols must be gone. Any remaining deprecated usages must be ones the user chose to defer. - Give the user a short report:
- What changed (toolchain, dependencies, call sites).
- Deprecations deferred, with file locations and their removal version (9.0, ~1 year, or a future release).
- Non-code follow-ups: the Play Console Location Purpose Declaration, and
optionally the new off-route traffic incident cards, which are on by
default when the traffic layer is enabled. They can be disabled with
setTrafficIncidentCardsEnabled(false)onNavigationView/NavigationFragmentif the app's UX needs that.
Verification checklist
- AGP >= 9.0.1 with the Gradle version that AGP requires, Gradle JDK >=
17;
compileSdk/targetSdk37; NavSDK dependency at 8.0.x. - Imports still
com.google.android.libraries.navigation.*;NavigationApi.getNavigator(...)initialization unchanged;RouteStatusstill used as an enum. - No references to
showTrafficLights,showStopSigns, oronGpsAvailabilityUpdate. - Exhaustive
RouteStatushandling coversROUTING_TIMEOUT;RouteStatus.NETWORK_ERRORhandling retained. -
getNavigatoronErrorhandlesErrorCode.NETWORK_ERRORwith a retry (it can now fire fromgetNavigator(Application, ...)). -
kotlin-reflect/ Glide declared only if the app uses them directly;androidx.car.app>= 1.3.0 if Android Auto is used. -
StylingOptionsis not parcelled; terrain isn't offered during navigation. - Deprecations either migrated (including
SupportNavigationFragmentin layout XML) or listed in the report as deferred. - Debug and release builds succeed; user reminded about the Play Location Purpose Declaration.