Jetpack Navigation

O componente de arquitetura de navegação simplifica a implementação da navegação e ajuda a visualizar o fluxo dela no seu app. A biblioteca oferece diversos benefícios, incluindo:

  • Processamento automático de transações de fragmentos
  • Processamento correto de Para cima e Voltar por padrão
  • Comportamento padrão para animações e transições
  • Links diretos como uma operação diferenciada
  • Implementação de padrões de IU de navegação (como gavetas de navegação e navegação inferior) com pouco trabalho extra
  • Segurança de tipo ao transmitir informações durante a navegação
  • Ferramentas do Android Studio para visualizar e editar o fluxo de navegação de um app

Pré-requisitos

Neste codelab, você trabalhará com o app de exemplo abaixo:

Todos os fragmentos e atividades já foram criados para você. Você usará o componente de navegação para conectá-los. Ao fazer isso, implemente o seguinte:

  • Gráfico de navegação visual
  • Navegação por destino e ação
  • Animações de transição
  • Navegação no menu, navegação na parte inferior e navegação na gaveta do menu
  • Transmissão de argumento com segurança de tipo
  • Links diretos

Pré-requisitos

  • Conhecimento básico sobre Kotlin (este codelab está em Kotlin)
  • Android Studio 3.2 ou versões mais recentes
  • Emulador ou dispositivo com API 14 ou mais recente

Buscar o código

Clone o codelab de navegação do GitHub:

$ git clone https://github.com/googlecodelabs/android-navigation

Se preferir, faça o download do repositório como um arquivo ZIP:

Download do ZIP

Instalar o Android Studio 3.3 ou versões mais recentes

Verifique se você está usando o Android Studio 3.3 ou mais recente. Isso é necessário para as ferramentas de navegação do Android Studio.

Se for necessário fazer o download de uma versão recente do Android Studio, acesse aqui.

Visão geral da navegação

O componente de navegação consiste em três partes principais, que trabalham juntas em harmonia. São eles:

  1. Gráfico de navegação (novo recurso XML): este é um recurso que contém todas as informações relacionadas à navegação em um local centralizado. Isso inclui todos os locais do app, conhecidos como destinos, e os possíveis caminhos que um usuário pode seguir pelo seu app.
  2. NavHostFragment (visualização XML de layout): este é um widget especial que pode ser adicionado ao layout. Ele exibe destinos diferentes do seu gráfico de navegação.
  3. NavController (objeto Kotlin/Java): este é um objeto que rastreia a posição atual no gráfico de navegação. Ele orquestra a troca de conteúdo de destino no NavHostFragment à medida que você percorre um gráfico de navegação.

Quando você navegar, usará o objeto NavController, informando-o para onde quer ir ou qual caminho quer seguir no seu gráfico de navegação. O NavController mostrará o destino adequado no NavHostFragment.

Essa é a ideia básica. Veja como isso funciona na prática, começando pelo novo recurso de gráfico de navegação.

Destinos

O componente de navegação introduz o conceito de destino. Um destino é qualquer local em que é possível navegar no app, geralmente um fragmento ou uma atividade. Eles são aceitos imediatamente, mas também é possível criar seus próprios tipos de destino personalizados, se necessário.

O gráfico de navegação é um novo tipo de recurso que define todos os caminhos possíveis que um usuário pode seguir em um app. Ela mostra visualmente todos os destinos que podem ser alcançados de determinado destino. O Android Studio exibe o gráfico no Navigation Editor. Veja o gráfico de navegação inicial que você criará para seu app:

Início, Etapa um e Etapa dois

Como explorar o Navigation Editor

1. Abra res/navigation/mobile_navigation.xml.

2. Clique em Design para entrar no modo Design:

Você verá o seguinte:

O gráfico de navegação mostra os destinos disponíveis. As setas entre os destinos são chamadas ações. Você aprenderá mais sobre as ações depois.

3. Clique em um destino para ver os atributos dele.

4. Clique em qualquer ação, representada por uma seta, para ver os atributos dela.

Anatomia de um arquivo XML de navegação

Todas as mudanças feitas no Navigation Editor gráfico mudam o arquivo XML subjacente, de forma semelhante à que o Layout Editor modifica o XML do layout.

Clique na guia Text:

Você verá um XML como este:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
    app:startDestination="@+id/home_dest">

    <!-- ...tags for fragments and activities here -->

</navigation>

Aviso:

  • O <navigation> é o nó raiz de todos os gráficos de navegação.
  • O <navigation> contém um ou mais destinos, representados pelos elementos <activity> ou <fragment>.
  • O app:startDestination é um atributo que especifica o destino que é iniciado por padrão quando o usuário abre o app pela primeira vez.

Veja o destino de um fragmento:

<fragment
    android:id="@+id/flow_step_one_dest"
    android:name="com.example.android.codelabs.navigation.FlowStepFragment"
    tools:layout="@layout/flow_step_one_fragment">
    <argument
        .../>

    <action
        android:id="@+id/next_action"
        app:destination="@+id/flow_step_two_dest">
    </action>
</fragment>

Aviso:

  • O android:id define um ID para o fragmento que pode ser usado para referenciar o destino em outro lugar no XML e no seu código.
  • O android:name declara o nome da classe totalmente qualificada do fragmento a ser instanciado quando você navega para esse destino.
  • O tools:layout especifica qual layout deve ser exibido no editor gráfico.

Algumas tags <fragment> também contêm <action>, <argument>, e <deepLink>, que serão abordados mais adiante.

O app de exemplo começa com alguns destinos no gráfico. Nesta etapa, você adicionará um novo destino. É necessário adicionar um destino ao gráfico de navegação para poder navegar até ele.

1. Abra res/navigation/mobile_navigation.xml e clique na guia Design.

2. Clique no ícone New Destination e selecione "settings_fragment".

O resultado é um novo destino, que renderiza uma visualização do layout do fragmento na visualização de design.

Também é possível editar o arquivo XML diretamente para adicionar destinos:

mobile_navigation.xml

<fragment
    android:id="@+id/settings_dest"
    android:name="com.example.android.codelabs.navigation.SettingsFragment"
    android:label="@string/settings"
    tools:layout="@layout/settings_fragment" />

No momento, você tem esse gráfico de navegação incrível, mas ele ainda não está sendo usando para navegar.

Atividades e navegação

O componente de navegação segue a orientação descrita nos Princípios de navegação. Esses princípios recomendam o uso de atividades como pontos de entrada para o app. As atividades também terão uma navegação global, como a navegação inferior.

Em comparação, os fragmentos serão os layouts reais específicos do destino.

Para que tudo isso funcione, é necessário modificar os layouts da atividade para que contenham um widget especial chamado NavHostFragment. Um NavHostFragment alterna diferentes destinos de fragmentos para dentro e para fora enquanto você navega no gráfico de navegação.

Um layout simples compatível com navegação semelhante à imagem acima tem a seguinte aparência. Veja um exemplo de código em res/layout-470dp/navigation_activity.xml:

<LinearLayout
    .../>
    <androidx.appcompat.widget.Toolbar
        .../>
    <fragment
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:id="@+id/my_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/mobile_navigation"
        app:defaultNavHost="true"
        />
    <com.google.android.material.bottomnavigation.BottomNavigationView
        .../>
</LinearLayout>

Aviso:

  • Este é um layout para uma atividade. Ele contém a navegação global, incluindo uma navegação inferior e uma barra de ferramentas
  • android:name="androidx.navigation.fragment.NavHostFragment" e app:defaultNavHost="true" conectam o botão "Voltar" do sistema ao NavHostFragment
  • app:navGraph="@navigation/mobile_navigation" associa o NavHostFragment a um gráfico de navegação. O gráfico de navegação especifica todos os destinos a que o usuário pode navegar nesse NavHostFragment.

Por fim, quando um usuário faz algo como clicar em um botão, é preciso acionar um comando de navegação. Uma classe especial chamada NavController é o que aciona as trocas de fragmento no NavHostFragment.

// Command to navigate to flow_step_one_dest
findNavController().navigate(R.id.flow_step_one_dest)

Você precisa transmitir um ID de ação ou de destino para navegar. Esses são os IDs definidos no XML do gráfico de navegação. Esse é um exemplo de transmissão de ID de destino.

O NavController é eficiente porque, quando você chama métodos como navigate() ou popBackStack(),, ele converte esses comandos nas operações de framework adequadas com base no tipo de destino para o qual você está navegando ou de onde está vindo. Por exemplo, quando você chama o navigate() com um destino de atividade, o NavController chama startActivity() em seu nome.

Há algumas maneiras de associar um objeto NavController ao seu NavHostFragment. No Kotlin, é recomendável usar uma das seguintes funções de extensão, dependendo se você está chamando o comando de navegação em um fragmento, uma atividade ou uma visualização:

É sua vez de navegar usando o NavController. Você pressionará o botão Navigate To Destination para navegar até o destino flow_step_one_dest, que é um FlowStepFragment:

1. Abra HomeFragment.kt.

2. Conecte navigate_destination_button a onViewCreated().

HomeFragment.kt

val button = view.findViewById<Button>(R.id.navigate_destination_button)
button?.setOnClickListener {
    findNavController().navigate(R.id.flow_step_one_dest, null)
}

3. Execute o app e clique no botão Navigate To Destination. O botão navega até o destino flow_step_one_dest.

O código do listener de clique ficaria assim:

val button = view.findViewById<Button>(R.id.navigate_destination_button)
button?.setOnClickListener(
        Navigation.createNavigateOnClickListener(R.id.flow_step_one_dest, null)
)

Cada chamada navigate() tem uma transição padrão não muito animadora associada a ela, conforme mostrado abaixo:

Da página inicial, o usuário clica em "Navigate to destination" e vai para a primeira etapa.

A transição padrão, assim como outros atributos associados à chamada, pode ser modificada com a inclusão de um conjunto de NavOptions. NavOptions usa um padrão Builder que permite substituir e configurar apenas as opções necessárias. Há também uma DSL ktx para NavOptions, que é a que você usará.

Para transições animadas, é possível definir recursos de animação XML na pasta de recursos anim e usar essas animações para transições. Veja alguns exemplos no código do app:

Adicionar uma transição personalizada

Atualize o código para que, ao pressionar o botão Navigate To Destination, uma animação de transição personalizada seja exibida.

1. Abra HomeFragment.kt.

2. Defina um NavOptions e transmita-o para a chamada de navigate() até navigate_destination_button.

val options = navOptions {
    anim {
        enter = R.anim.slide_in_right
        exit = R.anim.slide_out_left
        popEnter = R.anim.slide_in_left
        popExit = R.anim.slide_out_right
    }
}
view.findViewById<Button>(R.id.navigate_destination_button)?.setOnClickListener {
    findNavController().navigate(R.id.flow_step_one_dest, null, options)
}

3. Remova o código adicionado na etapa 5, se ainda estiver lá.

4. Verifique se, ao tocar no botão Navigate To Destination , o fragmento desliza para a tela e se, ao tocar em "Voltar", ele desliza para fora da tela.

Ações

O sistema de navegação também permite navegar por ações. Como mencionado anteriormente, as linhas mostradas no gráfico de navegação são representações visuais das ações.

A navegação por ações tem os seguintes benefícios sobre a navegação por destino:

  • É possível ver os caminhos de navegação no seu app.
  • As ações podem conter outros atributos associados que você pode configurar, como uma animação de transição, valores de argumentos e comportamento da pilha de retorno.
  • Para navegar, é possível usar o plug-in Safe Args, que será exibido em breve.

Veja a aparência e XML da ação que conecta flow_step_one_dest e flow_step_two_dest:

<fragment
    android:id="@+id/flow_step_one_dest"
    android:name="com.example.android.codelabs.navigation.FlowStepFragment">

    <argument
        .../>

    <action
        android:id="@+id/next_action"
        app:destination="@+id/flow_step_two_dest">
    </action>
</fragment>

<fragment
    android:id="@+id/flow_step_two_dest"
    android:name="com.example.android.codelabs.navigation.FlowStepFragment">
    <!-- ...removed for simplicity-->
</fragment>

Aviso:

  • As ações estão aninhadas dentro do destino de onde você navegará.
  • A ação inclui um argumento de destino que se refere a flow_step_two_dest. Esse é o ID para onde você navegará.
  • O ID da ação é "next_action"

Veja outro exemplo da ação que conecta flow_step_two_dest a home_dest:

<fragment
    android:id="@+id/home_dest"
    android:name="com.example.android.codelabs.navigation.HomeFragment"
    .../>

<fragment
    android:id="@+id/flow_step_two_dest"
    android:name="com.example.android.codelabs.navigation.FlowStepFragment">

    <argument
        .../>

    <action
        android:id="@+id/next_action"
        app:popUpTo="@id/home_dest">
    </action>
</fragment>

Aviso:

  • O mesmo ID next_action é usado para a ação que conecta flow_step_two_dest a home_dest. É possível navegar usando o ID next_action partindo de flow_step_one_dest ou flow_step_two_dest. Esse é um exemplo de como as ações podem fornecer um nível de abstração e podem navegar para outro lugar, dependendo do contexto.
  • O atributo popUpTo é usado. Essa ação remove os fragmentos da pilha de retorno até você chegar a home_dest.

É hora de conectar o botão Navigate with Action para que ele faça jus ao nome.

1. Abra o arquivo mobile_navigation.xml no modo Design .

2. Arraste uma seta de home_dest para flow_step_one_dest:

3. Com a seta de ação selecionada (azul), mude as propriedades da ação para que:

  • ID = next_action
  • Transição para Enter = slide_in_right
  • Transição para sair = slide_out_left
  • Transição para Pop Enter = slide_in_left
  • Transição para Pop Exit = slide_out_right

4. Clique na guia Text

Observe a ação next_action adicionada recentemente no destino home_dest:

mobile_navigation.xml

<fragment android:id="@+id/home_dest"
        ...>

        <action android:id="@+id/next_action"
            app:destination="@+id/flow_step_one"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right" />

5. Abra HomeFragment.kt.

6. Adicione um listener de clique ao navigate_action_button.

HomeFragment.kt

 view.findViewById<Button>(R.id.navigate_action_button)?.setOnClickListener(
        Navigation.createNavigateOnClickListener(R.id.next_action, null)
)

7. Verifique se agora, ao tocar em Navigate To Action, você navega até a próxima tela.

Safe Args

O componente de navegação tem um plug-in para Gradle chamado Safe args que gera classes simples de objetos e builders para acesso com segurança de tipo a argumentos especificados para destinos e ações.

O Safe Args permite que você remova códigos como este ao transmitir valores entre destinos:

val username = arguments?.getString("usernameKey")

Em vez disso, substitua-o por um código que gerou setters e getters.

val username = args.username

Transmitir um valor usando o Safe Args

1. Abra o arquivo build.gradle do projeto e observe o plug-in Safe Args:

build.gradle

dependencies {
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$navigationVersion"
    //...
    }

2. Abra o arquivo app/build.gradle e observe o plug-in aplicado:

app/build.gradle

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'androidx.navigation.safeargs.kotlin'

android {
   //...
}

3. Abra o mobile_navigation.xml, e observe como os argumentos são definidos no destino flow_step_one_dest.

mobile_navigation.xml

<fragment
    android:id="@+id/flow_step_one_dest"
    android:name="com.example.android.codelabs.navigation.FlowStepFragment"
    tools:layout="@layout/flow_step_one_fragment">
    <argument
        android:name="flowStepNumber"
        app:argType="integer"
        android:defaultValue="1"/>

    <action...>
    </action>
</fragment>

Usando a tag <argument>, o Safe Args gera uma classe chamada FlowStepFragmentArgs.

Como o XML inclui um argumento chamado flowStepNumber, especificado por android:name="flowStepNumber", a classe gerada FlowStepFragmentArgs incluirá uma variável flowStepNumber com getters e setters.

4. Abra FlowStepFragment.kt.

5. Comente a linha de código mostrada abaixo:

FlowStepFragment.kt

// Comment out this line
// val flowStepNumber = arguments?.getInt("flowStepNumber")

Esse código antigo não tem segurança de tipo. É melhor usar o Safe Args.

6. Atualize o FlowStepFragment para que use a classe FlowStepFragmentArgs gerada pelo código. Isso receberá os argumentos FlowStepFragment de maneira segura:

FlowStepFragment.kt

val safeArgs: FlowStepFragmentArgs by navArgs()
val flowStepNumber = safeArgs.flowStepNumber

Classes de rota do Safe Args

Também é possível usar o Safe Args para navegar de maneira segura, com ou sem a adição de argumentos. Faça isso usando as classes de rota geradas.

As classes de rotas são geradas para cada destino diferente com ações. A classe de rotas inclui métodos para todas as ações que um destino tem.

Por exemplo, o listener de clique navigate_action_button em HomeFragment.kt pode ser alterado para:

HomeFragment.kt

// Note the usage of curly braces since we are defining the click listener lambda
view.findViewById<Button>(R.id.navigate_action_button)?.setOnClickListener {
    val flowStepNumberArg = 1
    val action = HomeFragmentDirections.nextAction(flowStepNumberArg)
    findNavController().navigate(action)
}

Os componentes de Navigation incluem uma classe NavigationUI e as extensões navigation-ui-ktx do Kotlin. NavigationUI tem métodos estáticos que associam itens de menu com destinos de navegação, e navigation-ui-ktx é um conjunto de funções de extensão que também faz isso. Se a NavigationUI encontra um item de menu com o mesmo ID de um destino no gráfico atual, ela configura o item de menu para navegar até esse destino.

Usar NavigationUI com um menu "Opções"

Uma das formas mais fáceis de usar a NavigationUI é simplificar a configuração do menu "opções". Em particular, a NavigationUI simplifica o gerenciamento do callback de onOptionsItemSelected.

1. Abra MainActivity.kt.

Observe como você já possui o código para inflar o menu overflow_menu em onCreateOptionsMenu.

2. Abra res/menu/overflow_menu.xml.

3. Atualize o menu flutuante para incluir o settings_dest.

overflow_menu.xml

<item
    android:id="@+id/settings_dest"
    android:icon="@drawable/ic_settings"
    android:menuCategory="secondary"
    android:title="@string/settings" />

4. Abra MainActivity.kt.

5. Faça com que NavigationUI gerencie onOptionsItemSelected com o método auxiliar onNavDestinationSelected. Caso o item do menu não seja destinado a navegação, use super.onOptionsItemSelected.

MainActivity.kt

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return item.onNavDestinationSelected(findNavController(R.id.my_nav_host_fragment))
            || super.onOptionsItemSelected(item)
}

6. Execute o app. É preciso ter um menu funcional ActionBar que navegue até SettingsFragment.

Usar NavigationUI para configurar a navegação inferior

O código já contém o código de layout XML para implementar a navegação inferior. Por isso, você verá a barra de navegação inferior. Mas ele não navega para lugar nenhum.

1. Abra res/layout/navigation_activity/navigation_activity.xml (h470dp) e clique na guia Texto.

Observe como o código de layout XML para navegação inferior está lá e se refere a bottom_nav_menu.xml.

<com.google.android.material.bottomnavigation.BottomNavigationView
    android:id="@+id/bottom_nav_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:menu="@menu/bottom_nav_menu" />

2. Abra res/menu/bottom_nav_menu.xml.

Observe como há dois itens para a navegação inferior e que os IDs deles correspondem aos destinos do gráfico de navegação:

bottom_nav_menu.xml

<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@id/home_dest"
        android:icon="@drawable/ic_home"
        android:title="@string/home" />
    <item
        android:id="@id/deeplink_dest"
        android:icon="@drawable/ic_android"
        android:title="@string/deeplink" />
</menu>

Vamos fazer a navegação inferior, de fato, fazer algo usando a NavigationUI.

3. Abra MainActivity.kt.

4. Implemente o método setupBottomNavMenu usando setupWithNavController(bottomNavigationView: BottomNavigationView, navController: NavController).

MainActivity.kt

private fun setupBottomNavMenu(navController: NavController) {
    val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav_view)
    bottomNav?.setupWithNavController(navController)
}

Agora sua navegação inferior funciona!

Usar a NavigationUI para configurar uma gaveta de navegação

Por fim, vamos usar NavigationUI para configurar a navegação lateral e a gaveta de navegação, incluindo o gerenciamento da ActionBar e da navegação superior adequada. Essa opção aparecerá se você tiver uma tela grande o suficiente ou se a tela for muito curta para a navegação inferior.

Primeiro, observe como o código XML de layout adequado já está no app.

1. Abra navigation_activity.xml e navigation_activity.xml (w960dp).

Observe que os dois layouts contêm uma NavigationView conectada a nav_drawer_menu. Na versão para tablet (w960dp), a NavigationView fica sempre na tela. Em dispositivos menores, a NavigationView é aninhada em um DrawerLayout.

Para começar a implementar a navegação NavigationView:

2. Abra MainActivity.kt.

3. Implemente o método setupNavigationMenu usando setupWithNavController(navigationView: NavigationView, navController: NavController). Observe como essa versão do método aceita uma NavigationView, mas não uma BottomNavigationView.

MainActivity.kt

private fun setupNavigationMenu(navController: NavController) {
    val sideNavView = findViewById<NavigationView>(R.id.nav_view)
    sideNavView?.setupWithNavController(navController)
}

Agora, o menu de visualização de navegação será exibido na tela, mas não afetará a ActionBar.

A configuração da ActionBar requer a criação de uma instância de AppBarConfiguration. O objetivo da AppBarConfiguration é especificar as opções de configuração desejadas para suas barras de ferramentas, de recolhimento e de ações. As opções de configuração incluem se a barra precisa gerenciar um layout de gaveta e quais destinos são considerados destinos de nível superior.

Os destinos de nível superior são os destinos do nível raiz do seu app. Eles não exibem um botão "para cima" na barra de apps, e exibem o ícone de gaveta se o destino usa um layout de gaveta.

4. Crie um AppBarConfiguration transmitindo um conjunto de IDs de destino de nível superior e o layout de gaveta.

MainActivity.kt

val drawerLayout : DrawerLayout? = findViewById(R.id.drawer_layout)
appBarConfiguration = AppBarConfiguration(
        setOf(R.id.home_dest, R.id.deeplink_dest),
        drawerLayout)

Agora que você tem uma AppBarConfiguration, pode chamar NavigationUI.setupActionBarWithNavController. Isso fará o seguinte:

  • Mostrará um título na ActionBar com base no rótulo do destino
  • Exibirá o botão "Para cima" sempre que você não estiver em um destino de nível superior
  • Exibirá um ícone de gaveta (ícone de hambúrguer) quando estiver em um destino de nível superior

5. Implemente o setupActionBarWithNavController.

MainActivity.kt

private fun setupActionBar(navController: NavController,
                           appBarConfig : AppBarConfiguration) {
    setupActionBarWithNavController(navController, appBarConfig)
}

Também é necessário que a NavigationUI gerencie o que acontece quando o botão "Para cima" é pressionado.

6. Modifique onSupportNavigationUp e chame NavigationUI.navigateUp usando a mesma AppBarConfiguration.

MainActivity.kt

override fun onSupportNavigateUp(): Boolean {
    return findNavController(R.id.my_nav_host_fragment).navigateUp(appBarConfiguration)
}

7. Execute o código. Se você abrir o app na tela dividida, é necessário ter uma gaveta de navegação funcionando. O ícone para cima e o ícone da gaveta devem ser exibidos nos momentos adequados e funcionar corretamente.

Adicionar novos destinos a uma NavigationView é fácil. Quando a gaveta de navegação estiver funcionando com uma navegação para cima e para baixo, basta adicionar o novo item de menu.

8. Abra menu/nav_drawer_menu.xml.

9. Adicione um novo item de menu a settings_dest.

<item
    android:id="@+id/settings_dest"
    android:icon="@drawable/ic_settings"
    android:title="@string/settings" />

Agora, suas gavetas de navegação mostram a tela de configurações como um destino. Bom trabalho!

Os componentes de navegação também incluem compatibilidade com link direto. Links diretos são uma forma de ir para o meio da navegação do seu app, seja de um link de URL ou de uma intent pendente de uma notificação.

Uma vantagem de usar a biblioteca de navegação para gerenciar links diretos é garantir que os usuários comecem no destino certo com a pilha de retorno apropriada vinda de outros pontos de entrada, como widgets de apps, notificações ou links da Web (tratados na próxima etapa).

O Navigation oferece uma classe NavDeepLinkBuilder para construir uma PendingIntent que levará o usuário a um destino específico.

Usaremos o NavDeepLinkBuilder para conectar um widget de app a um destino.

1. Abra DeepLinkAppWidgetProvider.kt.

2. Adicione uma PendingIntent construída com o NavDeepLinkBuilder:

DeepLinkAppWidgetProvider

val args = Bundle()
args.putString("myarg", "From Widget");
val pendingIntent = NavDeepLinkBuilder(context)
        .setGraph(R.navigation.mobile_navigation)
        .setDestination(R.id.deeplink_dest)
        .setArguments(args)
        .createPendingIntent()

remoteViews.setOnClickPendingIntent(R.id.deep_link_button, pendingIntent)

Aviso:

  • O setGraph inclui o gráfico de navegação.
  • O setDestination especifica para onde o link é direcionado.
  • O setArguments inclui todos os argumentos que você quer transmitir para o link direto.

3. Adicione o widget de link direto à tela inicial. Toque na tela inicial e mantenha-a pressionada para ver a opção de adicionar um widget.

Tocar e manter pressionado

Rolar para baixo para encontrar o widget

Quando terminar, você terá um widget de link direto.

4. Toque no widget e verifique se o destino do Android abre com o argumento correto. A indicação "From Widget" aparece no topo, já que é o argumento que você transmitiu em DeepLinkAppWidgetProvider.

5. Verifique se pressionar o botão "Voltar" leva você ao destino do home_dest.

A pilha de retorno para um link direto é determinada usando o gráfico de navegação transmitido. Se a atividade explícita que você escolheu tiver uma atividade pai, essas atividades também serão incluídas.

A pilha de retorno é gerada usando os destinos especificados com app:startDestination. Neste app, temos apenas uma atividade e um nível de navegação. Assim, a pilha de retorno levará você ao destino home_dest.

A navegação mais complicada pode incluir gráficos de navegação aninhados. O app:startDestination em cada nível dos gráficos aninhados determina a pilha de retorno. Para mais informações sobre links diretos e gráficos aninhados, confira os Princípios de navegação.

Um dos usos mais comuns de um link direto é permitir que um link da Web abra uma atividade no seu app. Tradicionalmente, você usaria um filtro de intent e associaria um URL à atividade que quer abrir.

A biblioteca de navegação simplifica esse processo e permite mapear URLs diretamente para destinos no seu gráfico de navegação.

O <deepLink> é um elemento que pode ser adicionado a um destino no gráfico. Cada elemento <deepLink> tem um único atributo obrigatório: app:uri.

Além da correspondência com URI direto, os seguintes recursos são compatíveis:

  • Os URIs sem um esquema são considerados http e https. Por exemplo, www.example.com corresponderá a http://www.example.com e https://www.example.com.
  • É possível usar marcadores na forma de {placeholder_name} para corresponder a um ou mais caracteres. O valor de String do marcador está disponível no pacote de argumentos, que tem uma chave com o mesmo nome. Por exemplo, http://www.example.com/users/{id} corresponderá a http://www.example.com/users/4.
  • Você pode usar o caractere curinga .* para criar correspondência com zero ou mais caracteres.
  • O NavController gerenciará automaticamente as intents ACTION_VIEW e procurará links diretos correspondentes.

Nesta etapa, você adicionará um link direto a www.example.com.

1. Abra mobile_navigation.xml.

2. Adicione um elemento <deepLink> ao destino deeplink_dest.

mobile_navigation.xml

<fragment
    android:id="@+id/deeplink_dest"
    android:name="com.example.android.codelabs.navigation.DeepLinkFragment"
    android:label="@string/deeplink"
    tools:layout="@layout/deeplink_fragment">

    <argument
        android:name="myarg"
        android:defaultValue="Android!"/>

    <deepLink app:uri="www.example.com/{myarg}" />
</fragment>

3. Abrir AndroidManifest.xml

4. Adicione a tag nav-graph. Isso garantirá que o filtro de intent adequado seja gerado.

AndroidManifest.xml

<activity android:name=".MainActivity">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>

    <nav-graph android:value="@navigation/mobile_navigation" />
</activity>

5. Inicie o app usando um link direto. Há duas maneiras de fazer isso:

  • Use adb:
adb shell am start -a android.intent.action.VIEW -d "http://www.example.com/urlTest" 
  • Navegue pelo Google app É possível colocar www.example.com/urlTest na barra de pesquisa, e a janela de desambiguação será exibida. Selecione Codelab de navegação.

Abrir usando a barra de pesquisa

(não no Chrome)

Caixa de diálogo de desambiguação

De qualquer forma, a mensagem "urlTest" aparecerá na tela. Isso foi transmitido do URL para o fragmento.

Há mais uma parte do app do codelab para você testar: o botão de carrinho de compras.

Este é um resumo das habilidades que você aprendeu durante este codelab. Esta etapa não inclui comentários, então experimente por conta própria:

  1. Crie uma nova classe de fragmento.
  2. Adicione o fragmento como um destino ao gráfico de navegação.
  3. Faça o ícone do carrinho de compras abrir sua nova classe de fragmento, usando NavigationUI para gerenciar o menu.

Você já conhece os conceitos básicos do componente de navegação. Neste codelab, você aprendeu sobre:

  • Estrutura do gráfico de navegação
  • NavHostFragment e NavController
  • Como navegar para destinos específicos
  • Como navegar por ação
  • Como transmitir argumentos entre destinos, incluindo o uso do novo plug-in Safe Args
  • Como navegar usando menus, navegação inferior e gavetas de navegação
  • Como navegar pelo link direto


Você pode continuar explorando esse app ou começar a usar a navegação no seu app.

Há muito mais para testar, como:

  • Retirar destinos da pilha de retorno (ou qualquer manipulação de pilha de retorno)
  • Gráficos de navegação aninhados
  • Navegação condicional
  • Adição de compatibilidade com novos destinos

Para saber mais sobre o componente de navegação, confira a documentação. Se você tem interesse em conhecer outros componentes de arquitetura, consulte os seguintes codelabs: