---
title: "App Shortcuts no Android com Kotlin em 2026: atalhos estáticos, dinâmicos e fixados"
url: "https://kotlin.dev.br/blog/app-shortcuts-android-kotlin-2026/"
markdown_url: "https://kotlin.dev.br/blog/app-shortcuts-android-kotlin-2026.MD"
description: "Crie App Shortcuts no Android com Kotlin: atalhos estáticos, dinâmicos, fixados e long-lived, intents, ranking, limites, testes e boas práticas."
date: "2026-09-05"
author: "Karina Melo"
---

# App Shortcuts no Android com Kotlin em 2026: atalhos estáticos, dinâmicos e fixados

Crie App Shortcuts no Android com Kotlin: atalhos estáticos, dinâmicos, fixados e long-lived, intents, ranking, limites, testes e boas práticas.


**Resposta rápida:** use **App Shortcuts no Android** para levar o usuário diretamente a tarefas frequentes sem obrigá-lo a abrir a home do app e repetir a navegação. Declare **atalhos estáticos** em XML para ações universais e estáveis, publique **atalhos dinâmicos** com `ShortcutManagerCompat` para destinos personalizados, permita **atalhos fixados** quando a pessoa quiser colocar uma ação na tela inicial e marque como **long-lived** apenas conversas ou entidades que precisam participar de superfícies do sistema. Cada atalho deve abrir um destino válido, ter rótulo curto, ícone claro e comportamento seguro mesmo após logout, atualização ou restauração do processo.

Um toque longo no ícone pode virar “Nova tarefa”, “Escanear produto”, “Abrir pedido recente” ou “Conversar com Ana”. Essa economia de poucos segundos é valiosa em apps usados várias vezes por dia — logística, vendas, mensagens, finanças, saúde, delivery e ferramentas internas. O recurso, porém, não é um menu secreto para despejar funcionalidades. Bons atalhos representam **tarefas**, não departamentos do aplicativo.

Este guia mostra quando usar cada tipo, como configurar `shortcuts.xml`, publicar atalhos com Kotlin, integrar com Compose e deep links, atualizar destinos, medir uso e evitar os erros que aparecem em produção.

Antes de fixar números de limites ou detalhes de API, consulte a [documentação oficial de App Shortcuts](https://developer.android.com/develop/ui/views/launch/shortcuts). Launchers e versões do Android podem apresentar o recurso de formas diferentes; projete para degradação segura.

## Qual tipo de App Shortcut escolher?

A decisão principal é simples:

| Tipo | Quem cria | Melhor uso | Pode mudar com frequência? |
|---|---|---|---|
| Estático | Desenvolvedor, em XML | Ação igual para todos, como “Nova tarefa” | Não; muda com atualização do app |
| Dinâmico | App, em runtime | Conversa, projeto, loja ou pedido relevante | Sim |
| Fixado | Usuário, após solicitação do app | Ação que merece ícone próprio na tela inicial | O usuário controla a presença |
| Long-lived | App, como propriedade do atalho dinâmico | Conversas e entidades usadas por superfícies do sistema | Sim, com identidade estável |

Em geral, comece com dois ou três atalhos realmente úteis. A ordem e a quantidade visível dependem do launcher, então a experiência principal nunca pode depender de todos aparecerem.

### Regra de produto

Um atalho é bom quando completa esta frase:

> “A pessoa toca aqui para **fazer algo específico agora**.”

“Pedidos” é apenas uma seção. “Acompanhar pedido atual” é uma tarefa. “Clientes” é uma seção. “Cadastrar cliente” é uma tarefa. Essa diferença melhora descoberta, acessibilidade e mensuração.

## Atalhos estáticos com `shortcuts.xml`

Atalhos estáticos funcionam bem para ações que não dependem de conta, histórico ou personalização. Crie o arquivo `res/xml/shortcuts.xml`:

```xml
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
    <shortcut
        android:shortcutId="nova_tarefa"
        android:enabled="true"
        android:icon="@drawable/ic_shortcut_add"
        android:shortcutShortLabel="Nova tarefa"
        android:shortcutLongLabel="Criar uma nova tarefa">

        <intent
            android:action="android.intent.action.VIEW"
            android:targetPackage="br.dev.exemplo"
            android:targetClass="br.dev.exemplo.MainActivity"
            android:data="https://exemplo.com/tarefas/nova" />

    </shortcut>
</shortcuts>
```

Categorias de shortcut não são tags de SEO nem agrupamentos visuais livres: elas comunicam semântica ao sistema. Use a categoria de conversa somente quando o destino representar uma conversa real.

Depois, referencie o XML na `Activity` principal do `AndroidManifest.xml`:

```xml
<activity
    android:name=".MainActivity"
    android:exported="true">

    <meta-data
        android:name="android.app.shortcuts"
        android:resource="@xml/shortcuts" />

    <!-- filtros normais da Activity -->
</activity>
```

Use IDs estáveis e legíveis. Trocar `nova_tarefa` por um UUID em cada build impede o sistema de reconhecer continuidade. Também mantenha o rótulo curto de verdade: launchers podem truncar textos longos.

> **Cuidado:** atalhos estáticos não devem carregar identificadores de usuário, tokens, pedido atual ou qualquer estado que envelheça. Para isso existem atalhos dinâmicos.

## Abrindo o destino com deep link

O atalho não deve conhecer detalhes internos da árvore de Composables. Ele entrega uma `Intent`; uma fronteira de navegação transforma a URI em destino tipado. É o mesmo princípio do guia de [App Links e deep links com Kotlin](/blog/app-links-deep-links-android-kotlin-2026/).

```kotlin
sealed interface AppDestination {
    data object Home : AppDestination
    data object NovaTarefa : AppDestination
    data class Pedido(val id: String) : AppDestination
}

fun Intent.toDestination(): AppDestination {
    val uri = data ?: return AppDestination.Home
    val segments = uri.pathSegments

    return when {
        segments == listOf("tarefas", "nova") -> AppDestination.NovaTarefa
        segments.size == 2 && segments[0] == "pedidos" ->
            AppDestination.Pedido(segments[1])
        else -> AppDestination.Home
    }
}
```

Valide host, esquema, caminho e parâmetros antes de navegar. Um atalho pode sobreviver a atualização, backup ou mudança de sessão. Se o pedido não existe mais, abra uma tela de estado vazio com saída clara; não deixe a Activity fechar silenciosamente.

Em Compose, processe a entrada em um ponto único e também trate novas intents quando a Activity já estiver aberta:

```kotlin
class MainActivity : ComponentActivity() {
    private val shortcutDestinations = MutableSharedFlow<AppDestination>(
        extraBufferCapacity = 1,
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        shortcutDestinations.tryEmit(intent.toDestination())

        setContent {
            AppRoot(shortcutDestinations)
        }
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        setIntent(intent)
        shortcutDestinations.tryEmit(intent.toDestination())
    }
}
```

Se o app usa Navigation Compose ou Navigation 3, converta `AppDestination` para a rota adotada pelo projeto. Não chame `navigate()` em vários lugares em resposta à mesma intent, pois isso cria telas duplicadas. O guia de [Navigation 3 com Compose](/blog/navigation-3-compose-android-2026/) ajuda a estruturar destinos tipados.

## Atalhos dinâmicos com `ShortcutManagerCompat`

Atalhos dinâmicos devem refletir contexto recente e legítimo: as conversas mais usadas, o projeto ativo ou a entrega em andamento. A biblioteca AndroidX Core permite manter uma implementação compatível:

```kotlin
fun publicarAtalhoDePedido(
    context: Context,
    pedido: Pedido,
) {
    val intent = Intent(
        Intent.ACTION_VIEW,
        "https://exemplo.com/pedidos/${pedido.id}".toUri(),
        context,
        MainActivity::class.java,
    )

    val shortcut = ShortcutInfoCompat.Builder(
        context,
        "pedido_${pedido.id}",
    )
        .setShortLabel("Pedido ${pedido.codigo}")
        .setLongLabel("Acompanhar pedido ${pedido.codigo}")
        .setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut_package))
        .setIntent(intent)
        .build()

    ShortcutManagerCompat.pushDynamicShortcut(context, shortcut)
}
```

`pushDynamicShortcut()` é útil quando o aplicativo aprende que uma entidade acabou de se tornar relevante. Para publicar um conjunto calculado, use as operações de atalhos dinâmicos da API compatível conforme a estratégia do projeto.

O código de produção precisa responder:

- qual evento torna o atalho relevante?
- quando ele deixa de ser relevante?
- o ID continuará o mesmo após sincronização?
- o rótulo expõe informação privada na tela do aparelho?
- o destino funciona offline?
- o que acontece depois do logout?

Não atualize atalhos em cada recomposição, abertura de tela ou emissão de `Flow`. O sistema aplica limites de frequência a operações de publicação. Atualize quando a lista relevante realmente mudar e evite loops de escrita.

## Ranking e seleção: mostre o que ajuda agora

O launcher dispõe de pouco espaço. Em vez de publicar tudo, selecione os destinos com uma regra explicável.

Exemplo de pontuação:

```kotlin
data class CandidatoAtalho(
    val id: String,
    val titulo: String,
    val ultimoAcessoEpoch: Long,
    val fixadoPeloUsuario: Boolean,
    val disponivel: Boolean,
)

fun selecionarAtalhos(
    candidatos: List<CandidatoAtalho>,
    limite: Int,
): List<CandidatoAtalho> = candidatos
    .asSequence()
    .filter { it.disponivel }
    .sortedWith(
        compareByDescending<CandidatoAtalho> { it.fixadoPeloUsuario }
            .thenByDescending { it.ultimoAcessoEpoch },
    )
    .take(limite)
    .toList()
```

Na prática, atalhos fixados são controlados pelo launcher e não devem ser confundidos com itens apenas “favoritados” dentro do app. O exemplo mostra uma regra de produto para priorizar candidatos; consulte o estado real das APIs antes de remover ou desabilitar qualquer atalho.

Boas fontes de relevância:

1. ação concluída recentemente;
2. frequência de uso com decaimento temporal;
3. entidade favoritada explicitamente;
4. tarefa ativa com prazo curto;
5. disponibilidade local e permissão atual.

Evite usar dados sensíveis ou inferências opacas para ranking. “Última conversa aberta” é compreensível. “Pessoa com maior probabilidade de receber cobrança” não deve aparecer inesperadamente no launcher.

## Atalho fixado na tela inicial

Um atalho fixado ganha um ícone próprio, próximo aos apps e widgets. Ofereça isso depois que o usuário demonstrar intenção: ao favoritar uma loja, acompanhar uma rota todos os dias ou usar repetidamente uma ação.

```kotlin
fun solicitarAtalhoFixado(
    context: Context,
    projetoId: String,
    projetoNome: String,
): Boolean {
    if (!ShortcutManagerCompat.isRequestPinShortcutSupported(context)) {
        return false
    }

    val shortcut = ShortcutInfoCompat.Builder(context, "projeto_$projetoId")
        .setShortLabel(projetoNome)
        .setLongLabel("Abrir projeto $projetoNome")
        .setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut_project))
        .setIntent(
            Intent(
                Intent.ACTION_VIEW,
                "https://exemplo.com/projetos/$projetoId".toUri(),
                context,
                MainActivity::class.java,
            ),
        )
        .build()

    return ShortcutManagerCompat.requestPinShortcut(context, shortcut, null)
}
```

A solicitação não garante que o launcher adicionará o atalho: pode haver confirmação do usuário, falta de suporte ou política do dispositivo. Mostre a opção como melhoria, nunca como etapa obrigatória de onboarding.

Para uma presença que exibe informação e muda visualmente, talvez um [widget com Jetpack Glance](/blog/glance-widgets-android-kotlin-2026/) seja melhor. A diferença é útil:

- **atalho:** inicia uma tarefa;
- **widget:** mostra estado e pode oferecer poucas ações;
- **notificação:** alerta sobre um evento;
- **deep link:** define como uma URL chega a um destino.

## Conversas e atalhos long-lived

Apps de mensagens podem publicar atalhos associados a pessoas e marcá-los como long-lived. Isso permite integração mais rica com superfícies de conversa do Android, desde que o app mantenha identidade consistente para a pessoa e o canal.

Conceitualmente:

```kotlin
val pessoa = Person.Builder()
    .setName(contato.nome)
    .setKey(contato.id)
    .setImportant(contato.favorito)
    .build()

val shortcut = ShortcutInfoCompat.Builder(context, "conversa_${contato.id}")
    .setShortLabel(contato.nome)
    .setPerson(pessoa)
    .setLongLived(true)
    .setIntent(abrirConversaIntent(contato.id))
    .build()
```

Não marque qualquer tela como conversa para ganhar visibilidade. O atalho precisa representar comunicação real e deve se alinhar às notificações daquela conversa. Foto, nome e conteúdo podem aparecer fora do app; respeite preferências de privacidade, perfil de trabalho e bloqueio de tela.

## Login, permissões e estado expirado

Todo atalho é uma entrada externa. Trate estes cenários antes de publicar:

### Usuário deslogado

Guarde o destino solicitado, leve ao login e retome somente depois de autenticação bem-sucedida. Não inclua token de sessão na URI.

### Entidade removida

Exiba “Este pedido não está mais disponível” e ofereça voltar à lista. Em seguida, remova ou desabilite o atalho dinâmico obsoleto quando apropriado.

### Permissão negada

Um atalho “Escanear” pode chegar à câmera sem permissão. Explique o valor, solicite no contexto e ofereça alternativa. Siga o guia de [permissões Android com Kotlin](/blog/permissoes-android-kotlin-2026/).

### Sem rede

Se o destino existe no cache, abra em modo offline. Caso contrário, mostre estado de conexão e retry. Uma arquitetura [offline-first no Android](/blog/android-offline-first-kotlin-2026/) evita que o atalho pareça quebrado.

### Processo já aberto

Trate `onNewIntent()` e defina corretamente o comportamento da Activity. Teste para que tocar duas vezes não empilhe destinos duplicados.

## Ícones, rótulos e acessibilidade

O ícone precisa ser reconhecível em tamanho pequeno e funcionar com máscaras e estilos do launcher. Prefira desenho simples, bom contraste e recurso específico para o atalho. Não reutilize uma ilustração detalhada de onboarding.

Para os textos:

- comece com verbo quando a ação for o principal: “Criar tarefa”, “Escanear item”;
- use substantivo específico quando abrir uma entidade: “Pedido 4821”, “Equipe Mobile”;
- não dependa apenas de cor ou ícone para diferenciar ações;
- evite emoji como substituto de ícone;
- localize rótulos com recursos de string;
- não coloque texto promocional como “Oferta imperdível”.

O atalho também precisa abrir uma tela acessível. Revise foco, descrição de componentes e tamanho de toque com o guia de [acessibilidade no Android e Compose](/blog/acessibilidade-android-compose-kotlin-2026/).

## Como testar App Shortcuts

Teste em pelo menos um launcher real além do emulador principal. Fabricantes podem variar apresentação, quantidade visível e confirmação de pin.

Checklist manual:

1. instale o app limpo e pressione o ícone por alguns segundos;
2. confirme rótulo, ícone, ordem e truncamento;
3. abra cada atalho com o processo encerrado;
4. abra novamente com o app em foreground e background;
5. teste usuário autenticado e deslogado;
6. remova a entidade de destino e tente o atalho antigo;
7. desligue rede e repita;
8. altere idioma e tamanho de fonte;
9. solicite um atalho fixado e cancele a confirmação;
10. atualize o app sem limpar dados e verifique IDs existentes.

Para validar a resolução de uma intent via ADB:

```bash
adb shell am start \
  -a android.intent.action.VIEW \
  -d "https://exemplo.com/pedidos/4821" \
  br.dev.exemplo
```

Esse comando testa o contrato do destino, mas não substitui o toque real no launcher. Para cobertura automatizada da tela aberta, combine testes instrumentados e fluxos de UI descritos no guia de [testes Android com Compose e Maestro](/guias/testes-android-compose-maestro/).

## Analytics sem contar abertura duas vezes

Meça o atalho no ponto em que a entrada é interpretada, antes da navegação, e passe uma origem interna como `app_shortcut`. Não adicione informação sensível à URL pública apenas para analytics.

Eventos úteis:

- `app_shortcut_opened`, com tipo e ID lógico não sensível;
- `app_shortcut_destination_unavailable`;
- `app_shortcut_pin_requested`;
- `app_shortcut_pin_supported`;
- conclusão da tarefa iniciada pelo atalho.

A métrica importante não é apenas abertura. Compare a taxa de conclusão e o tempo até a ação com o fluxo iniciado pela home. Um atalho que recebe muitos toques acidentais e poucas conclusões precisa de rótulo ou seleção melhor.

Evite registrar o evento uma vez em `onCreate()` e novamente no Composable. Modele a intent como evento consumível, preserve o ID da entrada durante a navegação e deduplique conforme a arquitetura de analytics do app.

## Erros comuns

### Publicar atalhos demais

O launcher mostra poucos e pode ignorar o restante. Priorize. Se o usuário precisa estudar uma lista, a lista pertence ao app.

### Usar ID instável

IDs aleatórios quebram atualização, remoção e continuidade de atalhos fixados. Derive o ID de uma entidade estável, sem usar dado pessoal em texto puro quando isso expõe informação.

### Colocar token na URI

Intents e logs podem expor dados. O atalho leva a um identificador; autenticação e autorização continuam sendo responsabilidade do app e do backend.

### Esquecer o logout

Remova ou desabilite atalhos dinâmicos vinculados à conta quando a sessão terminar. Um rótulo com nome de cliente pode vazar contexto mesmo que a tela exija login.

### Atualizar em excesso

Publicação frequente encontra rate limits e gasta recursos. Calcule a lista quando eventos de domínio mudarem a relevância, não em timer curto.

### Confundir shortcut com background work

O atalho inicia uma interação. Sincronização confiável e adiável pertence ao [WorkManager](/blog/workmanager-kotlin-android-2026/); tarefa contínua visível pode exigir [foreground service](/blog/foreground-service-android-kotlin-2026/). Não tente manter o processo vivo depois do toque sem justificativa.

## Checklist de produção

Antes de liberar App Shortcuts, confirme:

- [ ] cada item representa uma tarefa específica;
- [ ] atalhos estáticos não dependem de estado variável;
- [ ] atalhos dinâmicos usam IDs estáveis;
- [ ] rótulos são curtos, localizados e não promocionais;
- [ ] ícones permanecem legíveis no launcher;
- [ ] URIs são validadas antes da navegação;
- [ ] login, logout e autorização foram testados;
- [ ] destino removido possui fallback útil;
- [ ] o app funciona quando o processo estava morto;
- [ ] `onNewIntent()` não duplica navegação;
- [ ] atualizações respeitam limites do sistema;
- [ ] dados privados não aparecem no rótulo sem necessidade;
- [ ] analytics registra origem uma única vez;
- [ ] o fluxo principal continua acessível sem atalhos.

## Perguntas frequentes

### Quantos App Shortcuts devo criar?

Crie poucos e priorizados — normalmente duas a quatro tarefas já permitem validar valor. O número efetivamente exibido varia por launcher e dispositivo. Consulte `maxShortcutCountPerActivity` nas APIs da plataforma quando precisar ajustar publicação dinâmica, mas não trate o máximo técnico como meta de produto.

### App Shortcut funciona com Jetpack Compose?

Sim. O launcher entrega uma `Intent` à Activity; Compose entra depois, quando o app converte essa entrada em estado ou destino de navegação. O cuidado principal é tratar tanto `onCreate()` quanto `onNewIntent()` sem disparar navegação duplicada.

### Qual a diferença entre atalho estático e dinâmico?

O estático é declarado no APK e serve para ações universais que mudam raramente. O dinâmico é publicado em runtime e pode representar contexto personalizado, como conversa recente ou projeto ativo.

### Posso criar um atalho fixado sem confirmação?

Não conte com isso. A solicitação passa pelo launcher e normalmente depende de ação ou confirmação do usuário. Primeiro verifique suporte e trate retorno sem prometer que o ícone foi criado.

### Devo usar URL HTTPS ou uma action customizada?

URL HTTPS é uma boa escolha quando o destino também existe como contrato público e pode aproveitar App Links. Uma action explícita pode ser adequada para ação estritamente interna. Em ambos os casos, valide a entrada, mantenha IDs estáveis e não transporte segredos.

### App Shortcuts melhoram retenção?

Podem melhorar quando reduzem passos de uma tarefa frequente. Não há ganho automático: meça conclusão, recorrência e remoção. Atalho irrelevante vira ruído no launcher.

## Conclusão

App Shortcuts são uma camada pequena de interface com impacto desproporcional em tarefas recorrentes. A implementação robusta combina quatro decisões: escolher ações úteis, manter identidade estável, tratar a intent como entrada não confiável e atualizar somente quando a relevância muda.

Comece com um atalho estático para uma ação universal e um dinâmico para o contexto mais valioso do produto. Teste processo morto, logout, destino expirado e launcher real. Depois use analytics para responder à pergunta que importa: **o atalho ajudou a pessoa a concluir a tarefa mais rápido?** Se a resposta for sim, expanda com cuidado; se for não, simplifique em vez de publicar mais opções.
