Como declarar as tags que um aplicativo Android deve receber?
Com filtros de intent no manifesto, tentados numa ordem fixa: primeiro o conteúdo NDEF, depois as listas de tecnologia. Filtre pelo conteúdo que o seu aplicativo trata, em minúsculas. Duas mudanças recentes decidem se alguma coisa chega: os links da web vão para ACTION_VIEW a partir do Android 16, e o Android 17 exige a permissão de despacho na atividade.
Três níveis, um vencedor
Duas declarações vêm antes de qualquer filtro: a permissão android.permission.NFC e, para um aplicativo que não serve para nada sem NFC, o recurso android.hardware.nfc marcado como exigido, que a Google Play usa para esconder o aplicativo dos celulares sem o hardware.
O guia de NFC do Android lista então três intents de despacho da maior para a menor prioridade: ACTION_NDEF_DISCOVERED para uma tag cujo conteúdo NDEF é mapeado para um tipo, ACTION_TECH_DISCOVERED quando nenhuma atividade trata a primeira, e ACTION_TAG_DISCOVERED como último recurso.
O despacho para no primeiro nível em que uma atividade corresponde. Se várias corresponderem naquele nível o usuário recebe um seletor, que a referência de Tag apresenta como o desfecho que o projeto tenta evitar, já que mexer no celular para escolher em geral quebra a ligação.
O nível do NDEF lê um registro. A mesma referência diz que o sistema examina o primeiro registro da primeira mensagem, então uma mensagem que começa com um registro que o seu aplicativo ignora é, para o despacho, uma mensagem sobre outra coisa.
| Primeiro registro | Despachado como |
|---|---|
| Tipo bem conhecido, URI | Um URI montado a partir da carga útil |
| Tipo bem conhecido, texto | O tipo MIME text/plain |
| Mídia MIME | O tipo MIME que o registro declara |
| URI absoluto | Um URI montado a partir do campo de tipo |
| Tipo externo | Um URI que começa com vnd.android.nfc://ext/ |
| Vazio, desconhecido ou inalterado | Nada: o despacho recai nas tecnologias |
Filtrar pelo conteúdo
Um filtro ACTION_NDEF_DISCOVERED nomeia a ação, a categoria DEFAULT e um elemento data: um tipo MIME, ou um esquema com um host e um caminho.
Escreva cada parte em minúsculas. A referência de IntentFilter afirma que a correspondência de tipo MIME, de esquema e de host distingue maiúsculas de minúsculas, ao contrário das RFC de onde vêm. Quando um registro é mapeado para um URI, a referência de NdefRecord diz que o esquema é passado a minúsculas e não diz nada do host, então uma tag gravada com um host em maiúsculas pode escapar de um filtro escrito em minúsculas.
Filtre pelo que o seu aplicativo trata e por nada mais largo. O exemplo de despacho em primeiro plano do guia de NFC avançado registra todo tipo MIME com um comentário pedindo aos desenvolvedores que nomeiem só os de que precisam, e um filtro largo demais põe o aplicativo no seletor para tags que ele não consegue usar.
Os links da web já não são intents NDEF
A maior mudança recente diz respeito à tag mais comum. A partir do Android 16, afirma o guia de NFC do Android, uma tag que guarda um link http ou https dispara ACTION_VIEW em vez de ACTION_NDEF_DISCOVERED.
A partir do Android 17, a mesma tag mostra primeiro um aviso de abrir o link, e o link só abre quando o usuário responde a ele.
Um aplicativo que filtrava pelo próprio endereço https por ACTION_NDEF_DISCOVERED deixa portanto de receber essas tags nessas versões. A documentação aponta para os Android App Links para abrir um aplicativo a partir de um link desses.
A mudança se limita a http e https. A documentação não descreve nada parecido para os registros MIME, os tipos externos ou outros esquemas, que continuam passando pelo nível do NDEF.
Listas de tecnologia
ACTION_TECH_DISCOVERED precisa de um filtro de intent e de uma entrada meta-data que aponta para um recurso XML de elementos tech-list. A referência de NfcAdapter detalha a lógica: toda tecnologia dentro de uma tech-list tem de estar presente, e uma tech-list qualquer já basta.
Nomeie só as classes que todo celular do seu público oferece. A referência de TagTechnology torna MifareClassic, MifareUltralight e NfcBarcode opcionais, e um celular que não tem uma delas nunca a enumera, então uma lista de tecnologia que a exige nunca corresponde naquele celular, e nada avisa.
O que o Android 16 e o 17 exigem
A partir do Android 17, um aplicativo que mira um SDK acima do Android 16 tem de proteger cada atividade que recebe intents de NFC com android.permission.DISPATCH_NFC_MESSAGE, para que só o serviço de NFC do sistema possa abri-la. A mesma passagem acrescenta que o sistema não despacha intents de NFC para um aplicativo num estado parado: nunca aberto pelo usuário, ou parado à força.
A partir do Android 16, os usuários podem recusar as intents de tag aplicativo por aplicativo. isTagIntentAppPreferenceSupported() diz se o celular oferece o ajuste, isTagIntentAllowed() se o usuário deixou o seu aplicativo permitido, e ACTION_CHANGE_TAG_INTENT_PREFERENCE abre a página em que isso pode ser mudado.
E ACTION_TAG_DISCOVERED, o nível que pega tudo, está descontinuado a partir do Android 17, o que deixa os filtros de conteúdo e as listas de tecnologia como as duas portas de entrada mantidas.
Perguntas frequentes
Por que o meu filtro NDEF nunca dispara?
Confira as maiúsculas e minúsculas do tipo MIME, do esquema e do host, depois o primeiro registro da tag. No Android 16 e mais recente, confira se a tag guarda um link da web, e no Android 17 se a atividade carrega a permissão de despacho.
Por que aparece um seletor se o meu aplicativo está instalado?
Outro aplicativo corresponde no mesmo nível. Estreite o seu filtro para um conteúdo que só o seu aplicativo trata, ou nomeie o seu aplicativo na tag com um registro de aplicação do Android.
Um registro de aplicação do Android substitui os filtros de intent?
Não. O sistema tenta os filtros de intent primeiro. Se a atividade correspondente não pertencer ao aplicativo nomeado, ou se várias corresponderem, ele abre o aplicativo nomeado, e abre a Google Play quando esse aplicativo não está instalado.
O meu aplicativo ainda consegue receber uma tag que guarda um link da web?
Pelos Android App Links, para os quais a documentação aponta a partir do Android 16. Um filtro NDEF no endereço https já não recebe a tag, e a partir do Android 17 o link espera que o usuário responda a um aviso.