Como receber dados simples de outros apps

Da mesma forma que um app envia dados a outros apps, ele também pode receber dados. Pense em como os usuários interagem com seu app e nos tipos de dados que você quer receber de outros apps. Por exemplo, para um app de rede social, pode ser interessante receber conteúdo de texto de outro app, como um URL da Web.

Muitas vezes os usuários enviam dados ao app por meio do Android Sharesheet ou do resolvedor de intents. Todos os dados recebidos têm um tipo MIME definido pelo app provedor. Seu app pode receber dados enviados por outro app de três formas:

  • Uma Activity com uma tag intent-filter correspondente no manifesto
  • Um ou mais objetos ChooserTarget retornados pelo ChooserTargetService
  • Atalhos de compartilhamento publicados pelo seu app. Eles substituem os objetos ChooserTarget. Os atalhos de compartilhamento só estão disponíveis em apps para o Android 10 (API de nível 29)

Os atalhos de compartilhamento e os objetos ChooserTarget são links diretos de compartilhamento direto para uma Activity específica no seu app. Em geral, eles representam uma pessoa e são exibidos pelo Android Sharesheet. Por exemplo, um app de mensagens de texto pode oferecer um atalho de compartilhamento para alguém que tem link direto para uma conversa com essa pessoa.

Como oferecer compatibilidade com tipos MIME

Seu app deve conseguir receber o maior número possível de tipos de MIME. Por exemplo, um app de mensagens usado para enviar texto, imagens e vídeos precisa ser compatível com o recebimento de text/*, image/* e video/*. Veja alguns tipos MIME comuns para o envio de dados simples no Android.

  • text/*: em, geral, o usuário remetente enviará text/plain, text/rtf, text/html, text/json.
  • image/*: em, geral, o usuário remetente enviará image/jpg, image/png, image/gif.
  • video/*: em, geral, o usuário remetente enviará video/mp4, video/3gp.
  • Os destinatários precisam se registrar para extensões de arquivo compatíveis: em geral, o usuário remetente enviará application/pdf.

Consulte o registro oficial IANA de tipos MIME de mídia. Você pode receber um tipo MIME de */*, mas isso não é recomendável, a menos que você seja totalmente capaz de processar qualquer tipo de conteúdo recebido.

Como criar excelentes alvos de compartilhamento

Quando um usuário toca em um alvo de compartilhamento associado a uma atividade específica, ele deve poder confirmar e editar o conteúdo compartilhado antes de usá-lo. Isso é especialmente importante no caso de dados de mensagens de texto.

O toque em qualquer alvo de compartilhamento direto deve levar o usuário a uma interface onde uma ação possa ser diretamente realizada no assunto do alvo. Evite mostrar uma desambiguação ao usuário ou levá-lo a uma interface não relacionada ao alvo tocado. Principalmente, não leve o usuário a uma interface de desambiguação de contatos em que ele precise confirmar ou selecionar novamente o contato para o compartilhamento, uma vez que isso já foi feito ao tocar no alvo no Android Sharesheet. Por exemplo, em um app de mensagens de texto, o toque em um alvo de compartilhamento direto deve levar o usuário a uma visualização de conversas com a pessoa selecionada. O teclado deve estar visível, e a mensagem deve ser preenchida previamente com os dados compartilhados.

Como receber dados com uma atividade

Atualizar seu manifesto

Os filtros de intent dizem ao sistema quais intents um componente de app tende a aceitar. Da mesma forma que você criou uma intent com a ação ACTION_SEND na lição Como enviar dados simples para outros apps, crie filtros de intent para poder receber intent com essa ação. O filtro de intent é definido no manifesto usando o elemento <intent-filter>. Por exemplo, se seu app processa conteúdo de mensagens de texto recebidas e uma única imagem, ou diversas imagens, de qualquer tipo, seu manifesto deve ser mais ou menos assim:

<activity android:name=".ui.MyActivity" >
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.SEND_MULTIPLE" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="image/*" />
    </intent-filter>
</activity>

Quando outro app tentar compartilhar qualquer um desses itens criando uma intent e transmitindo-a para startActivity(), seu app será listado como uma opção no Android Sharesheet ou no resolvedor de intents. Se o usuário selecionar seu app, a atividade correspondente (.ui.MyActivity no exemplo acima) será iniciada. Cabe a você processar o conteúdo corretamente no seu código e na IU.

Observação: para ver mais informações sobre filtros de intents e resolução de intents, leia Intents e filtros de intents

Processar o conteúdo recebido

Para processar o conteúdo enviado por um Intent, chame getIntent() para conseguir o objeto Intent. Assim que você tiver o objeto, poderá analisar o conteúdo dele e determinar o que fazer em seguida. Se for possível iniciar essa atividade de outras partes do sistema, como a tela de início, essa característica precisará ser considerada durante a análise da intent.

Verifique os dados recebidos com muita atenção, porque nunca se sabe o que outro app pode enviar. Por exemplo, o tipo MIME incorreto pode estar definido ou a imagem enviada pode ser grande demais. Além disso, lembre-se de processar dados binários em uma linha de execução separada, não na linha de execução principal (IU).

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    when {
        intent?.action == Intent.ACTION_SEND -> {
            if ("text/plain" == intent.type) {
                handleSendText(intent) // Handle text being sent
            } else if (intent.type?.startsWith("image/") == true) {
                handleSendImage(intent) // Handle single image being sent
            }
        }
        intent?.action == Intent.ACTION_SEND_MULTIPLE
                && intent.type?.startsWith("image/") == true -> {
                handleSendMultipleImages(intent) // Handle multiple images being sent
        }
        else -> {
            // Handle other intents, such as being started from the home screen
        }
    }
    ...
}

private fun handleSendText(intent: Intent) {
    intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
        // Update UI to reflect text being shared
    }
}

private fun handleSendImage(intent: Intent) {
    (intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM) as? Uri)?.let {
        // Update UI to reflect image being shared
    }
}

private fun handleSendMultipleImages(intent: Intent) {
    intent.getParcelableArrayListExtra<Parcelable>(Intent.EXTRA_STREAM)?.let {
        // Update UI to reflect multiple images being shared
    }
}

Java

void onCreate (Bundle savedInstanceState) {
    ...
    // Get intent, action and MIME type
    Intent intent = getIntent();
    String action = intent.getAction();
    String type = intent.getType();

    if (Intent.ACTION_SEND.equals(action) && type != null) {
        if ("text/plain".equals(type)) {
            handleSendText(intent); // Handle text being sent
        } else if (type.startsWith("image/")) {
            handleSendImage(intent); // Handle single image being sent
        }
    } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) {
        if (type.startsWith("image/")) {
            handleSendMultipleImages(intent); // Handle multiple images being sent
        }
    } else {
        // Handle other intents, such as being started from the home screen
    }
    ...
}

void handleSendText(Intent intent) {
    String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
    if (sharedText != null) {
        // Update UI to reflect text being shared
    }
}

void handleSendImage(Intent intent) {
    Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
    if (imageUri != null) {
        // Update UI to reflect image being shared
    }
}

void handleSendMultipleImages(Intent intent) {
    ArrayList<Uri> imageUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
    if (imageUris != null) {
        // Update UI to reflect multiple images being shared
    }
}

A atualização da IU após o recebimento dos dados pode ser tão simples quanto preencher um EditText ou mais complexa, como aplicar um filtro de foto interessante a uma imagem. Cabe ao seu app determinar o que acontece em seguida.

Garantir que os usuários reconheçam seu app

Seu app é representado pelo ícone e etiqueta correspondentes no Android Sharesheet e no resolvedor de intents. Ambos são definidos no manifesto. Você pode definir etiquetas de atividade ou de filtro de intent para fornecer mais contexto.

A partir do Android 10 (API de nível 29), o Android Sharesheet usará apenas os ícones definidos no manifesto da tag application. Os ícones configurados nas tags intent-filter e activity serão ignorados.

Observação: os melhores alvos de compartilhamento não precisam de uma etiqueta e um ícone na atividade ou no filtro de intents relacionados. Apenas o nome e o ícone do app de destino deve ser suficiente para que os usuários entendam o que acontecerá no momento de compartilhamento.

Como disponibilizar alvos de compartilhamento direto

O Compartilhamento direto foi introduzido no Android 6.0 (API de nível 23), permitindo aos apps disponibilizar objetos ChooserTarget por meio de um ChooserTargetService. Os resultados foram recuperados de forma reativa sob demanda, levando a um carregamento lento de alvos.

No Android 10 (API de nível 29), as APIs Direct Share de ChooserTargetService foram substituídas pela nova API Sharing Shortcuts. Em vez de recuperar os resultados de forma reativa sob demanda, a API Sharing Shortcuts permite que os apps publiquem alvos de compartilhamento direto com antecedência. O mecanismo de compartilhamento direto ChooserTargetService continuará funcionando, mas os alvos fornecidos dessa forma serão classificadas com menor prioridade do que qualquer outro alvo que use a API Sharing Shortcuts.

ShortcutManagerCompat é uma API AndroidX que oferece atalhos de compartilhamento de compatibilidade com versões anteriores da API DirectShare de ChooserTargetService. Essa é a maneira preferencial de publicar atalhos de compartilhamento e ChooserTargets. Veja as instruções abaixo.

Publicar alvos de compartilhamento direto

Você só pode usar atalhos dinâmicos para publicar alvos de compartilhamento direto. Siga as etapas abaixo para publicar alvos de compartilhamento direto usando a nova API.

  1. Declare elementos de alvos de compartilhamento no arquivo de recurso XML do app. Para ver detalhes, consulte Declarar um alvo de compartilhamento abaixo.
  2. Publique atalhos dinâmicos com categorias correspondentes aos alvos de compartilhamento declarados. Os atalhos podem ser adicionados, acessados, atualizados e removidos usando o ShortcutManager ou ShortcutManagerCompat no AndroidX. O método preferencial é usar a biblioteca de compatibilidade no AndroidX, porque ela oferece compatibilidade com versões anteriores do Android.

API Sharing Shortcuts

ShortcutInfo.Builder inclui métodos novos e aprimorados que oferecem mais informações sobre o alvo de compartilhamento:

setCategories()
Esse não é um método novo, mas agora as categorias também são usadas para filtrar atalhos que podem processar intents ou ações de compartilhamento. Consulte Declarar um alvo de compartilhamento para ver mais detalhes. Esse campo é obrigatório para atalhos que se destinam ao uso como alvos de compartilhamento.
setLongLived()

Especifica se um atalho é válido ou não quando o app cancelou a publicação dele ou o tornou invisível (como um atalho dinâmico ou fixado). Se um atalho é de longa duração, ele pode ser armazenado em cache por vários serviços do sistema, mesmo depois de ter tido a publicação cancelada como atalho dinâmico.

Fazer com que um atalho seja de longa duração pode melhorar a classificação dele. Consulte Como conseguir a melhor qualificação para ver mais detalhes.

setPerson(), setPersons()

Associa um ou mais objetos Person ao atalho. Pode ser usado para entender melhor o comportamento do usuário em diferentes apps e para ajudar os serviços de previsão do framework a melhorar as sugestões oferecidas em um ShareSheet. O acréscimo de informações de Person a um atalho é opcional, mas altamente recomendável se o alvo de compartilhamento for associado a uma pessoa. Alguns alvos de compartilhamento, como nuvens, não podem ser associados a uma pessoa.

A inclusão de um objeto Person específico com uma chave exclusiva em um alvo de compartilhamento e notificações relacionadas pode melhorar sua classificação. Consulte Como conseguir a melhor qualificação para ver mais detalhes.

Para um app de mensagens típico, é necessário publicar um atalho separado para cada contato, e o campo Person precisa conter as informações do contato. Se o alvo for associado a várias pessoas (como um bate-papo em grupo), adicione vários objetos Person a um único alvo de compartilhamento.

Ao publicar um atalho para uma única pessoa, inclua o nome completo dela em setLongLabel() e qualquer abreviação do nome, como apelido ou primeiro nome, em setShortLabel()

Para ver um exemplo de como publicar atalhos de compartilhamento, consulte o Exemplos de código de atalhos de compartilhamento (em inglês).

Como conseguir a melhor classificação

O Android Sharesheet mostra um número fixo de alvos de compartilhamento direto. Essas sugestões são ordenadas por classificação. É possível melhorar a classificação dos seus atalhos fazendo o seguinte:

  • Verifique se todos os atalhos são únicos e nunca são reutilizados por alvos diferentes.
  • Verifique se o atalho é de longa duração chamando setLongLived(true).
  • Ofereça uma classificação que possa ser usada para comparar atalhos do seu app na ausência de dados de treinamento. Consulte setRank(). Uma classificação mais baixa significa que o atalho é mais importante.

Para melhorar ainda mais a classificação, é altamente recomendável que apps sociais realizem todos os procedimentos acima e:

  • Forneçam objetos Person relevantes com uma chave configurada no seu atalho (consulte setPerson(), setPersons() e setKey()).
  • Vinculem seu atalho a notificações relevantes da mesma pessoa ou grupo de pessoas (consulte setShortcutId().). O shortcutId pode ser atribuído a qualquer atalho publicado anteriormente com setLongLived(true).

Para conseguir a melhor classificação possível, os apps sociais podem realizar todos os procedimentos acima e:

  • nos objetos Person definidos, fornecer um URI válido para um contato associado no dispositivo. Consulte setUri()

Veja um exemplo de atalho com todas as melhorias de classificação possíveis.

Kotlin

val person = Person.Builder()
  ...
  .setName(fullName)
  .setKey(staticPersonIdentifier)
  .setUri("tel:$phoneNumber") // alternatively "mailto:$email" or CONTENT_LOOKUP_URI
  .build()

val shortcutInfo = ShortcutInfoCompat.Builder(myContext, staticPersonIdentifier)
  ...
  .setShortLabel(firstName)
  .setLongLabel(fullName)
  .setPerson(person)
  .setLongLived(true)
  .setRank(personRank)
  .build()

Java

Person person = Person.Builder()
  ...
  .setName(fullName)
  .setKey(staticPersonIdentifier)
  .setUri("tel:"+phoneNumber) // alternatively "mailto:"+email or CONTENT_LOOKUP_URI
  .build();

ShortcutInfoCompat shortcutInfo = ShortcutInfoCompat.Builder(myContext, staticPersonIdentifier)
  ...
  .setShortLabel(firstName)
  .setLongLabel(fullName)
  .setPerson(person)
  .setLongLived(true)
  .setRank(personRank)
  .build();

Kotlin

val notif = NotificationCompat.Builder(myContext, channelId)
  ...
  .setShortcutId(staticPersonIdentifier)
  .build()

Java

Notification notif = NotificationCompat.Builder(myContext, channelId)
  ...
  .setShortcutId(staticPersonIdentifier)
  .build();

Como oferecer imagens de atalhos

Para criar um atalho de compartilhamento, é necessário adicionar uma imagem por meio do setIcon().

Os atalhos de compartilhamento podem aparecer em todas as superfícies do sistema e ser remodelados. Para garantir que seu atalho tenha a aparência pretendida, providencie um bitmap adaptável por meio de IconCompat.createWithAdaptiveBitmap().

Bitmaps adaptáveis devem seguir as mesmas diretrizes e dimensões estabelecidas para ícones adaptáveis. A forma mais comum de conseguir isso é dimensionar o bitmap quadrado pretendido para 72 x 72 dp e centralizá-lo em uma tela transparente de 108 x 108 dp.

Não ofereça imagens mascaradas para uma forma específica. Por exemplo, antes do Android 10 (API de nível 29), era comum oferecer avatares de usuário para ChooserTargets de compartilhamento direto mascarados na forma de um círculo. Agora, o Android Sharesheet e outras superfícies de sistema no Android 10 definem a forma e o tema de imagens de atalho. O método preferido para fornecer atalhos de compartilhamento, por meio do ShortcutManagerCompat, moldará automaticamente ChooserTargets de compartilhamento direto de versões anteriores em um círculo.

Declarar um alvo de compartilhamento

Os alvos de compartilhamento precisam ser declarados no arquivo de recursos do app, da mesma forma que as definições de atalhos estáticos. Adicione as definições de alvos de compartilhamento dentro do elemento raiz <shortcuts> no arquivo de recursos, junto com outras definições de atalhos estáticos. Cada elemento <share-targets> contém informações sobre o tipo de dados compartilhados, as categorias correspondentes e a classe de alvo que processarão a intent de compartilhamento. O código XML é semelhante a este:

<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
  <share-target android:targetClass="com.example.android.sharingshortcuts.SendMessageActivity">
    <data android:mimeType="text/plain" />
    <category android:name="com.example.android.sharingshortcuts.category.TEXT_SHARE_TARGET" />
  </share-target>
</shortcuts>

O elemento de dados em um alvo de compartilhamento é semelhante à especificação de dados em um filtro de intents. Cada alvo de compartilhamento pode ter várias categorias, que são usadas apenas para corresponder aos atalhos publicados de um app com as respectivas definições de alvo de compartilhamento. As categorias podem ter valores arbitrários definidos pelo app.

Caso o usuário selecione o atalho de compartilhamento no Android ShareSheet que corresponda ao exemplo de alvo de compartilhamento acima, o app receberá a seguinte intent de compartilhamento.

Action: Intent.ACTION_SEND
ComponentName: {com.example.android.sharingshortcuts /
                com.example.android.sharingshortcuts.SendMessageActivity}
Data: Uri to the shared content
EXTRA_SHORTCUT_ID: <ID of the selected shortcut>

Se o usuário abrir o alvo de compartilhamento a partir dos atalhos da tela de início, o app receberá a intent criada durante o acréscimo do atalho de compartilhamento a ShortcutManagerCompat. Por ser uma intent diferente, Intent.EXTRA_SHORTCUT_ID não estará disponível, e você terá que transmitir o ID manualmente se precisar dele.

Como usar o AndroidX para oferecer atalhos de compartilhamento e ChooserTargets

Para trabalhar com a biblioteca de compatibilidade do AndroidX, o manifesto do app precisa conter o conjunto de metadados de serviço seletor de alvo e de filtros de intent. Veja a API Direct Share atual ChooserTargetService.

Como esse serviço já está declarado na biblioteca de compatibilidade, o usuário não precisa declará-lo no manifesto do app. No entanto, o link da atividade de compartilhamento para o serviço precisa ser considerado como um provedor do seletor de alvo.

No exemplo a seguir, a implementação de ChooserTargetService é androidx.core.content.pm.ChooserTargetServiceCompat, que já está definido no AndroidX:

<activity
    android:name=".SendMessageActivity"
    android:label="@string/app_name"
    android:theme="@style/SharingShortcutsDialogTheme">
    <!-- This activity can respond to Intents of type SEND -->
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
    <!-- Only needed if you import the sharetarget AndroidX library that
         provides backwards compatibility with the old DirectShare API.
         The activity that receives the Sharing Shortcut intent needs to be
         taken into account with this chooser target provider. -->
    <meta-data
        android:name="android.service.chooser.chooser_target_service"
        android:value="androidx.sharetarget.ChooserTargetServiceCompat" />
</activity>

Perguntas frequentes sobre atalhos de compartilhamento

Quais são as principais diferenças entre a API Sharing Shortcuts atual e a API Direct Share ChooserTargetService antiga?

A API Sharing Shortcuts usa um modelo push, enquanto a antiga API Direct Share usa o modelo pull. Isso torna o processo de recuperação de alvos de compartilhamento muito mais rápido durante a preparação do ShareSheet. Do ponto de vista do desenvolvedor do app, com o uso da nova API, o app precisa listar os alvos de compartilhamento direto com antecedência. Também pode ser necessário atualizar a lista de atalhos sempre que o estado interno do app mudar (por exemplo, se um novo contato for adicionado a um app de mensagens).

O que pode acontecer se eu não migrar para as novas APIs Sharing Shortcuts?

No Android 10 (API de nível 29) e versões mais recentes, o Android Sharesheet priorizará os alvos de compartilhamento fornecidos por meio do ShortcutManager usando a API Sharing Shortcuts. Assim, seus alvos de compartilhamento publicados podem ser ocultados por alvos de compartilhamento de outros apps e nunca aparecer quando forem compartilhados.

Posso usar ChooserTargetService e as APIs Sharing Shortcuts e Direct Share no meu app para ser compatível com versões anteriores?

Não faça isso. Em vez disso, use as APIs da Biblioteca de Suporte ShortcutManagerCompat fornecidas. A combinação de dois conjuntos de APIs pode provocar um comportamento indesejado/inesperado durante a recuperação de alvos de compartilhamento.

Qual é a diferença entre os atalhos publicados para alvos de compartilhamento e os atalhos da tela de início (uso normal de atalhos ao tocar em ícones de apps e mantê-los pressionados na tela de início)?

Todos os atalhos publicados com a função de "alvo de compartilhamento" também são atalhos da tela de início e serão exibidos no menu quando o ícone do app for tocado e mantido pressionado. O limite máximo de atalhos por atividade também se aplica ao número total de atalhos que um app publica (alvos de compartilhamento e atalhos da tela de início herdados combinados).