Que limites do controlador o código Android tem de conferir em tempo de execução?
Tudo o que a referência expõe como um leitor e não como uma constante: o comprimento máximo de transceive, o suporte a APDU de comprimento estendido, o tempo limite, e quais classes de tecnologia opcionais aparecem. Dois celulares na mesma versão do Android podem responder de outro jeito, então o código lê esses valores na tag em mãos.
Quanto um comando consegue carregar
getMaxTransceiveLength(), em NfcA, NfcV ou IsoDep, devolve o maior número de bytes que uma chamada a transceive() consegue enviar. Ele depende do controlador do celular, e a referência não dá valor algum a presumir.
As APDU acrescentam um segundo limite. A referência de IsoDep explica que uma APDU padrão carrega no máximo 255 bytes de carga útil, 261 bytes ao todo, enquanto uma APDU de comprimento estendido carrega até 65535, e que alguns adaptadores não suportam a forma estendida. isExtendedLengthApduSupported() responde pelo celular em mãos.
Um cartão que espera APDU estendidas portanto funciona num celular e falha em outro rodando o mesmo código. Onde o cartão também aceita a forma padrão, recorra a ela em vez de presumir o suporte.
Quanto tempo o celular espera
setTimeout() em NfcA ou IsoDep define quanto tempo transceive() espera por uma resposta. A referência de NfcA sugere um valor mais alto para as operações que tomam tempo da tag, como a geração de uma chave, e observa que o valor volta ao padrão quando a ligação se fecha.
O próprio padrão não está documentado. Leia-o com getTimeout() em vez de fixar no código o número medido num celular, e defina o seu valor de novo depois de cada connect().
Quais classes existem
As classes opcionais são a outra variável. MifareClassic, MifareUltralight e NfcBarcode podem faltar por completo num celular, e NdefFormatable aparece só para as tags que o celular consegue formatar.
O único teste confiável é getTechList() na tag em mãos, já que a ausência é silenciosa. A página das classes de tecnologia cobre o que cada classe dá a você.
O que o usuário e o sistema desligam
getDefaultAdapter() devolve null quando o celular não tem controlador NFC, e isEnabled() devolve false quando o usuário desligou o NFC. A referência de NfcAdapter sugere mandar o usuário para Settings.ACTION_NFC_SETTINGS no segundo caso.
A partir do Android 16, um usuário também pode recusar as intents de tag de um aplicativo, o que isTagIntentAllowed() informa. O adaptador está ligado, o aplicativo está instalado, e as tags mesmo assim nunca chegam, então vale conferir isso antes de qualquer depuração.
A partir do nível de API 34, getNfcAntennaInfo() devolve o que o celular sabe das antenas dele, incluindo a posição delas em relação ao aparelho, e pode devolver null. Onde ele responde, um aplicativo consegue mostrar ao usuário onde segurar a tag em vez de descrever isso em palavras.
Perguntas frequentes
Que comprimento de transceive dá para presumir?
Nenhum. Leia getMaxTransceiveLength na tecnologia ligada e divida os comandos para caberem.
Por que uma APDU funciona num celular e falha em outro?
Ela pode usar a forma de comprimento estendido, que alguns adaptadores não suportam. Confira isExtendedLengthApduSupported e recorra às APDU padrão onde o cartão permitir.
Um tempo limite definido com setTimeout persiste?
Não. A referência diz que ele volta ao padrão quando a ligação é fechada, então defina-o de novo depois de cada connect.
Um aplicativo consegue descobrir onde fica a antena NFC?
A partir do nível de API 34, getNfcAntennaInfo devolve informações sobre as antenas, incluindo a posição relativa, quando o celular as oferece. Ele pode devolver null, então o aplicativo precisa de uma reserva.