Como detectar que uma tag saiu do campo?
No Android, a troca seguinte lança TagLostException, e a partir do nível de API 24 NfcAdapter.ignore() chama um ouvinte depois de a tag ficar fora por um atraso escolhido. No iOS, isAvailable passa a falso e o comando seguinte falha. Nenhuma das duas informa o momento em si, e uma tag que volta conta como nova.
No Android
O fluxo comum não tem evento de saída. A plataforma confere que uma tag descoberta continua presente, e o modo leitor deixa um aplicativo escolher com que frequência por EXTRA_READER_PRESENCE_CHECK_DELAY, que a referência do NfcAdapter descreve como o atraso que a plataforma usa nas verificações de presença. O que o aplicativo vê é a chamada de entrada e saída seguinte dele falhando com TagLostException, uma subclasse de IOException.
isConnected() não responde à pergunta. A referência do TagTechnology diz que ele devolve verdadeiro quando connect() foi concluído, close() não foi chamado e não se sabe que a tag esteja fora de alcance, sem atividade de rádio alguma: ele informa o que a plataforma já sabe, não uma verificação nova.
Para uma tag que fica parada, como uma num suporte de carro, NfcAdapter.ignore(), a partir do nível de API 24, é a ferramenta. Ele para a comunicação com a tag enquanto ela continua ao alcance e chama um OnTagRemovedListener depois de a tag ficar fora de alcance por debounceMs; uma tag que volta antes disso não é despachada de novo. A referência acrescenta três limites: o controlador sonda a cada 100 a 500 ms, então uma tag que entra e sai do alcance pode ser despachada de novo embora nunca tenha saído de verdade; outra tag cancela a chamada; e uma tag com identificador aleatório o derrota.
No iOS
Toda tag que o Core NFC entrega herda de NFCNDEFTag, cujo isAvailable passa a falso quando a tag é tirada do campo ou desconectada, segundo a referência do isAvailable. Nenhuma chamada do delegado informa isso: um aplicativo que precisa saber lê a propriedade, ou fica sabendo por um comando que falha com readerTransceiveErrorTagConnectionLost.
Uma conexão também consegue terminar enquanto a tag fica. Uma tag continua conectada até o aplicativo conectar em outra ou reiniciar a sondagem, segundo a referência do connect, e a nota da Apple sobre restartPolling() diz que as tags detectadas antes de um reinício ficam inválidas.
Uma sessão NDEF faz a espera sozinha. Com um delegado que recebe mensagens, a sessão reinicia a sondagem assim que as tags detectadas estão fora de alcance, como explica a página das várias tags, então uma tag mantida parada não é lida duas vezes seguidas.
Por que isso sempre atrasa
A saída é deduzida do silêncio. Um celular fica sabendo que uma tag foi embora quando uma verificação de presença ou um comando não recebe resposta, e a referência do NfcAdapter põe o intervalo de sondagem do controlador em 100 a 500 ms. O aplicativo fica sabendo da saída depois de a mão se mexer, nunca no momento em que ela se mexe.
Projete a interface em torno desse atraso. Uma gravação informada como feita antes de a chamada dela retornar é um palpite: mostre a conclusão quando a chamada retornar, e trate uma exceção como um resultado desconhecido, como explica a página das gravações interrompidas.
As leituras duplas começam aqui
Uma tag que sai e volta é uma descoberta nova. No Android ela chega como um objeto Tag novo, já que a referência do Tag cria um cada vez que a tag entra no alcance; no iOS a sessão a detecta de novo assim que ela saiu. A página do disparo duplo descreve como uma mão produz isso sem querer.
Um aplicativo que tem de agir uma vez por toque decide então o que conta como repetição. Comparar o identificador com o último lido, dentro de uma janela de tempo que o aplicativo escolhe, pega o caso comum, e ignore() faz o mesmo no Android para uma tag deixada parada. Nenhum dos dois funciona com identificadores aleatórios, onde o lado que recebe tem de tolerar repetições, a conclusão a que a página do disparo duplo chega para os servidores.
Perguntas frequentes
isConnected() me diz que a tag continua ali?
Não. Ele informa se o connect foi concluído e o close não foi chamado, sem tocar no rádio. A chamada de entrada e saída seguinte é o que diz isso a você.
Existe um evento quando uma tag sai no Android?
Só por NfcAdapter.ignore(), a partir do nível de API 24, cujo ouvinte dispara depois de a tag ficar fora de alcance pelo atraso que você escolher.
Existe um no iOS?
Nenhuma chamada do delegado informa isso. A propriedade isAvailable da tag passa a falso, e o comando seguinte falha com um erro de conexão perdida.
Por que o meu aplicativo lê a mesma tag duas vezes?
A tag saiu do campo e voltou, o que conta como uma descoberta nova. Compare identificadores dentro de uma janela de tempo, ou use ignore() no Android para uma tag que fica parada.