A navegação 3 representa uma mudança fundamental na forma como o Jetpack Compose processa o estado de navegação e oferece vantagens arquitetônicas significativas em relação à navegação 2.
Entenda as mudanças arquitetônicas e as etapas necessárias para migrar um app do Wear Compose da Navegação 2 para a Navegação 3.
Principais vantagens da Navigation 3
- Controle direto da pilha de retorno: o
NavBackStacké basicamente uma lista mutável de objetosNavKey, que representa o histórico de telas visitadas pelo usuário. Você controla exatamente como faria com qualquerMutableListdo Kotlin (add,removeLast,clear). Manipule diretamente a lista para realizar ações de navegação, como adicionar uma chave para avançar ou remover uma chave para voltar. - Design "Compose-First": a backstack é modelada como um estado observável padrão. A modificação do histórico de navegação se comporta exatamente como a atualização de qualquer outro estado do Compose, acionando automaticamente a recomposição para mostrar a tela atual.
- Segurança de tipo por padrão: as rotas baseadas em strings são eliminadas completamente. A navegação usa objetos de dados serializáveis e classes de dados.
- Apresentações dissociadas (estratégias de cena): a camada de transição da interface
(
NavDisplayeSwipeDismissableSceneStrategy) é totalmente separada do rastreamento de estado (NavBackStack), permitindo uma integração mais simples das transições de navegação integradas do Wear OS.
Etapas da migração
1. Atualizar dependências
Remova a dependência androidx.wear.compose:compose-navigation antiga e
introduza as novas dependências divididas do Navigation 3, além do suporte à
serialização do Kotlin.
Remova:
implementation("androidx.wear.compose:compose-navigation:...")
Adicionar:
implementation("androidx.navigation3:navigation3-runtime:...") // State logic
implementation("androidx.navigation3:navigation3-ui:...") // Display logic
implementation("androidx.wear.compose:compose-navigation3:...") // Wear gestures
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:...") // Requires compiler plugin
2. Atualizar destinos para implementar NavKey
Na Navegação 2, talvez você tenha usado strings ou objetos genéricos para o roteamento. Na
Navegação 3, você precisa implementar a interface de marcador NavKey e
anotar todos os objetos de tela com @Serializable.
Por que isso é necessário? Para garantir que o backstack possa ser salvo e restaurado após o encerramento do processo, o navigation3-runtime subjacente depende do kotlinx-serialization para serializar o estado.
Antes (Navigation 2: rotas genéricas com segurança de tipos):
sealed class Nav2Screen { data object Landing : Nav2Screen() data object List : Nav2Screen() }
Depois (Navigation 3 - NavKey + Serializable):
@Serializable sealed interface MigrationScreen : NavKey { @Serializable data object Landing : MigrationScreen @Serializable data object List : MigrationScreen }
3. Substitua a lógica de roteamento (NavController para NavBackStack)
Substitua seu NavController por um NavBackStack inicializado via
rememberNavBackStack. Você também precisa instanciar o
SwipeDismissableSceneStrategy especificamente para o Wear OS.
Antes (Navegação 2):
val navController = rememberSwipeDismissableNavController()
Depois (Navegação 3):
val backStack = rememberNavBackStack(MigrationScreen.Landing as NavKey) val strategy = rememberSwipeDismissableSceneStrategy<NavKey>()
4. Substitua NavHost por NavDisplay e a DSL entryProvider.
O contêiner NavHost e a DSL do builder composable("route") { ... } interna
são substituídos por NavDisplay e pela DSL {
entry<Key> { ... } } do entryProvider.
Antes (Navegação 2):
SwipeDismissableNavHost(navController = navController, startDestination = "menu") { composable("menu") { GreetingScreen( onShowList = { navController.navigate("list") } ) } composable("list") { ListScreen() } }
Depois (Navegação 3):
NavDisplay( backStack = backStack, sceneStrategies = listOf(strategy), entryProvider = entryProvider { entry<MigrationScreen.Landing> { GreetingScreen( onShowList = { backStack.add(MigrationScreen.List) } ) } entry<MigrationScreen.List> { ListScreen() } } )