Por que um comando expira, e quanto tempo o código deve esperar?
O Android deixa o código pôr um tempo de espera por tecnologia e o reinicia quando a conexão fecha; o padrão não é documentado, então leia-o em vez de supô-lo. O iOS não expõe tempo de espera algum. Nos dois casos a resposta a uma expiração em geral são menos comandos, e não uma espera mais longa.
O que o Android expõe
setTimeout() em NfcA ou IsoDep define quanto transceive() espera. Dois detalhes da referência decidem como ele é usado: o valor volta ao padrão quando a conexão fecha, então ele é posto de novo depois de cada connect(), e o próprio padrão não é documentado, então getTimeout() é o único jeito honesto de saber.
Um valor mais longo serve para operações que tomam tempo da tag, a geração de chaves sendo o exemplo da própria referência. Ele não faz uma tag responder se ela nunca responderia, e não ajuda uma tag que foi embora, que levanta TagLostException em vez disso, o assunto da página da tag perdida.
O modo leitor acrescenta um segundo relógio: o atraso que a plataforma usa para conferir que uma tag descoberta continua presente, posto pelo extra da verificação de presença, o que a página da saída cobre.
O que o iOS não expõe
O Core NFC não tem tempo de espera a definir. O aplicativo envia um comando e espera, e o framework informa readerTransceiveErrorRetryExceeded quando houve tentativas demais, ou um erro de conexão perdida quando a tag foi embora.
A sessão tem o limite próprio dela, uma invalidação sem duração documentada, o que a página da invalidação retoma. Então no iOS a única alavanca é quanto o aplicativo pede, e com que rapidez ele responde: na emulação de cartão a Apple avisa que uma resposta lenta pode ser lida pelo leitor como uma expiração.
O que uma ida e volta custa
Todo comando é uma ida e volta, e o orçamento de um toque é pequeno. O guia da emulação de cartão do Android põe um limite superior razoável em cerca de 1 KB de dados trocados em uns 300 ms, que é o parâmetro publicado mais claro para o que cabe enquanto uma mão fica parada.
Então leia nos blocos que o protocolo dá a você. Um READ de Tipo 2 devolve quatro páginas de uma vez, dezesseis bytes por um comando, como descreve a página do Tipo 2; uma leitura de Tipo 4 é limitada pelo máximo do próprio contêiner, e pedir menos que esse máximo custa comandos que não compram nada.
Projetar dentro da janela
Faça o trabalho antes do toque. Busque o que a troca precisa, monte os quadros, abra a conexão de rede, e guarde o tempo da tag para a tag: um aplicativo que chama um servidor enquanto segura uma tag pôs uma rede no caminho crítico de um gesto de mão.
Depois trate uma expiração como desconhecida em vez de falhada, sobretudo depois de uma gravação, e leia a tag de volta antes de decidir qualquer coisa. Uma nova tentativa que supõe que o comando anterior não fez nada é como um contador é incrementado duas vezes.
Perguntas frequentes
Qual é o tempo de espera padrão no Android?
Não é documentado. Leia-o com getTimeout na tecnologia que você abriu, e ponha o seu valor de novo depois de cada connect.
Dá para definir um tempo de espera no iOS?
Não. O Core NFC não expõe nenhum. Ele informa tentativas demais ou uma conexão perdida, e a sessão tem o limite próprio dela, não documentado.
Quanto dá para trocar num toque?
O guia da emulação de cartão do Android dá cerca de 1 KB em aproximadamente 300 ms como limite razoável, que é um parâmetro útil também para leitura.
Uma expiração é a mesma coisa que uma recusa?
Não. Uma recusa volta como uma palavra de estado ou um sinalizador de erro vindo da tag. Uma expiração quer dizer que nada voltou, então o resultado é desconhecido.