Este documento descreve tópicos avançados de NFC, como trabalhar com várias tecnologias de etiqueta, gravar em tags NFC e fazer envios em primeiro plano, o que permite que um aplicativo em primeiro plano processe intents mesmo quando outros aplicativos aplicam filtros para as mesmas.
Trabalhar com tecnologias de etiqueta compatíveis
Ao trabalhar com etiquetas NFC e dispositivos Android, o formato principal usado para ler e gravar dados nas etiquetas é NDEF. Quando um dispositivo faz a leitura de uma tag com dados NDEF, o Android oferece suporte
para analisar a mensagem e entregar a mensagem em um NdefMessage
quando
possível. No entanto, há casos em que você verifica uma tag que não contém dados NDEF ou quando esses dados não podem ser mapeados para um tipo MIME ou URI.
Nesses casos, você precisa abrir a comunicação diretamente com a tag e ler e gravar nela com seu próprio protocolo (em bytes brutos). O Android oferece suporte genérico para esses casos de uso com o
pacote android.nfc.tech
, descrito na Tabela 1. É possível usar o método getTechList()
para determinar as tecnologias compatíveis com a tag e criar o objeto TagTechnology
correspondente com uma das classes fornecidas por android.nfc.tech
.
Classe. | Descrição |
---|---|
TagTechnology |
A interface que todas as classes de tecnologia de etiquetas precisam implementar. |
NfcA |
Fornece acesso às propriedades NFC-A (ISO 14443-3A) e operações de E/S. |
NfcB |
Fornece acesso às propriedades NFC-B (ISO 14443-3B) e operações de E/S. |
NfcF |
Fornece acesso às propriedades da NFC-F (JIS 6319-4) e operações de E/S. |
NfcV |
Fornece acesso às propriedades NFC-V (ISO 15693) e operações de E/S. |
IsoDep |
Fornece acesso às propriedades ISO-DEP (ISO 14443-4) e operações de E/S. |
Ndef |
Fornece acesso a dados e operações NDEF em etiquetas NFC formatadas como NDEF. |
NdefFormatable |
Fornece operações de formato para etiquetas que podem ser formatadas como NDEF. |
As tecnologias de tag a seguir não precisam ter suporte de dispositivos Android.
Classe. | Descrição |
---|---|
MifareClassic |
Fornece acesso a propriedades MIFARE Classic e operações de E/S, se este dispositivo Android oferecer suporte a MIFARE. |
MifareUltralight |
Fornece acesso a propriedades MIFARE Ultralight e operações de E/S, se este dispositivo Android for compatível com MIFARE. |
Trabalhando com tecnologias de etiqueta e com o intent ACTION_TECH_DISCOVERED
Quando um dispositivo faz a leitura de uma etiqueta que tem dados NDEF, mas não pôde ser mapeada para um MIME ou URI, o sistema de expedição de etiquetas tenta iniciar uma atividade com a intent ACTION_TECH_DISCOVERED
. O ACTION_TECH_DISCOVERED
também é usado quando uma etiqueta com dados não NDEF é lida. Com esse substituto, você poderá trabalhar diretamente com os dados na tag se o sistema de expedição não puder analisá-los. As etapas básicas ao trabalhar com tecnologias de tag são as seguintes:
- Filtre por uma intent
ACTION_TECH_DISCOVERED
especificando as tecnologias de tag que você quer processar. Consulte Como filtrar intents NFC para ver mais informações. Em geral, o sistema de expedição de etiquetas tenta iniciar um intentACTION_TECH_DISCOVERED
quando uma mensagem NDEF não pode ser mapeada para um tipo MIME ou URI ou se a tag lida não continha dados NDEF. Para mais informações sobre como isso é determinado, consulte o sistema de expedição de etiquetas. - Quando o aplicativo receber a intent, extraia o objeto
Tag
dela:Kotlin
var tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
Java
Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
- Consiga uma instância de um
TagTechnology
chamando um dos métodos de fábricaget
das classes no pacoteandroid.nfc.tech
. É possível enumerar as tecnologias compatíveis da tag chamandogetTechList()
antes de chamar um método de fábricaget
. Por exemplo, para conseguir uma instância deMifareUltralight
de umTag
, faça o seguinte:Kotlin
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))
Java
MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
Ler e gravar em etiquetas
Ler e gravar em uma tag NFC envolve obter a etiqueta da intent e abrir a comunicação com a etiqueta. Você precisa definir sua própria pilha de protocolos para ler e gravar dados na tag. No entanto, lembre-se de que você ainda pode ler e gravar dados NDEF ao trabalhar diretamente com uma tag. Cabe a você decidir como quer estruturar as coisas. O exemplo a seguir mostra como trabalhar com uma tag MIFARE Ultralight.
Kotlin
package com.example.android.nfc import android.nfc.Tag import android.nfc.tech.MifareUltralight import java.io.IOException import java.nio.charset.Charset class MifareUltralightTagTester { fun writeTag(tag: Tag, tagText: String) { MifareUltralight.get(tag)?.use { ultralight -> ultralight.connect() Charset.forName("US-ASCII").also { usAscii -> ultralight.writePage(4, "abcd".toByteArray(usAscii)) ultralight.writePage(5, "efgh".toByteArray(usAscii)) ultralight.writePage(6, "ijkl".toByteArray(usAscii)) ultralight.writePage(7, "mnop".toByteArray(usAscii)) } } } fun readTag(tag: Tag): String? { return MifareUltralight.get(tag)?.use { mifare -> mifare.connect() val payload = mifare.readPages(4) String(payload, Charset.forName("US-ASCII")) } } }
Java
package com.example.android.nfc; import android.nfc.Tag; import android.nfc.tech.MifareUltralight; import android.util.Log; import java.io.IOException; import java.nio.charset.Charset; public class MifareUltralightTagTester { private static final String TAG = MifareUltralightTagTester.class.getSimpleName(); public void writeTag(Tag tag, String tagText) { MifareUltralight ultralight = MifareUltralight.get(tag); try { ultralight.connect(); ultralight.writePage(4, "abcd".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(5, "efgh".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(6, "ijkl".getBytes(Charset.forName("US-ASCII"))); ultralight.writePage(7, "mnop".getBytes(Charset.forName("US-ASCII"))); } catch (IOException e) { Log.e(TAG, "IOException while writing MifareUltralight...", e); } finally { try { ultralight.close(); } catch (IOException e) { Log.e(TAG, "IOException while closing MifareUltralight...", e); } } } public String readTag(Tag tag) { MifareUltralight mifare = MifareUltralight.get(tag); try { mifare.connect(); byte[] payload = mifare.readPages(4); return new String(payload, Charset.forName("US-ASCII")); } catch (IOException e) { Log.e(TAG, "IOException while reading MifareUltralight message...", e); } finally { if (mifare != null) { try { mifare.close(); } catch (IOException e) { Log.e(TAG, "Error closing tag...", e); } } } return null; } }
Usar o sistema de expedição em primeiro plano
O sistema de expedição em primeiro plano permite que uma atividade intercepte uma intent e reivindique prioridade sobre outras atividades que processem a mesma intent. O uso desse sistema envolve a criação de algumas estruturas de dados para que o sistema Android possa enviar os intents apropriados para o aplicativo. Para ativar o sistema de expedição em primeiro plano:
- Adicione o seguinte código no método
onCreate()
da sua atividade:- Crie um objeto
PendingIntent
mutável para que o sistema Android possa preenchê-lo com os detalhes da tag quando ela for lida.Kotlin
val intent = Intent(this, javaClass).apply { addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP) } var pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE)
Java
PendingIntent pendingIntent = PendingIntent.getActivity( this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_MUTABLE);
- Declare os filtros de intent para processar os intents que você quer interceptar. O sistema de expedição em primeiro plano verifica os filtros de intent especificados com o intent recebido quando o dispositivo faz a leitura de uma tag. Se corresponderem, o aplicativo processará o intent. Se não houver correspondência, o sistema de expedição em primeiro plano volta para o sistema de expedição de intents.
Especificar uma matriz
null
de filtros de intent e filtros de tecnologia define que você quer filtrar todas as tags que substituem a intentTAG_DISCOVERED
. O snippet de código abaixo processa todos os tipos MIME paraNDEF_DISCOVERED
. Processe apenas os necessários.Kotlin
val ndef = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED).apply { try { addDataType("*/*") /* Handles all MIME based dispatches. You should specify only the ones that you need. */ } catch (e: IntentFilter.MalformedMimeTypeException) { throw RuntimeException("fail", e) } } intentFiltersArray = arrayOf(ndef)
Java
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED); try { ndef.addDataType("*/*"); /* Handles all MIME based dispatches. You should specify only the ones that you need. */ } catch (MalformedMimeTypeException e) { throw new RuntimeException("fail", e); } intentFiltersArray = new IntentFilter[] {ndef, };
- Configurar uma matriz de tecnologias de etiqueta que o aplicativo quer processar. Chame o método
Object.class.getName()
para receber a classe da tecnologia que você quer oferecer.Kotlin
techListsArray = arrayOf(arrayOf<String>(NfcF::class.java.name))
Java
techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
- Crie um objeto
- Modifique os seguintes callbacks do ciclo de vida da atividade e adicione lógica para ativar e desativar a
remessa em primeiro plano quando a atividade perder (
onPause()
) e recuperar (onResume()
) o foco.enableForegroundDispatch()
precisa ser chamado na linha de execução principal e somente quando a atividade está em primeiro plano. ChamaronResume()
garante isso. Também é necessário implementar o callbackonNewIntent
para processar os dados da tag NFC lida.
Kotlin
public override fun onPause() { super.onPause() adapter.disableForegroundDispatch(this) } public override fun onResume() { super.onResume() adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray) } public override fun onNewIntent(intent: Intent) { val tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG) // do something with tagFromIntent }
Java
public void onPause() { super.onPause(); adapter.disableForegroundDispatch(this); } public void onResume() { super.onResume(); adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray); } public void onNewIntent(Intent intent) { Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); // do something with tagFromIntent }