Nozioni di base su NFC

Questo documento descrive le attività NFC di base che esegui in Android. Viene spiegato come inviare e ricevere dati NFC sotto forma di messaggi NDEF e vengono descritte le API framework Android che supportano queste funzionalità. Per argomenti più avanzati, inclusa una discussione sull'utilizzo di dati non NDEF, consulta la pagina NFC avanzata.

Esistono due casi d'uso principali per l'utilizzo dei dati NDEF e di Android:

  • Lettura di dati NDEF da un tag NFC
  • Trasmissione di messaggi NDEF da un dispositivo all'altro con Android BeamTM

La lettura dei dati NDEF da un tag NFC viene gestita con il sistema di invio dei tag, che analizza i tag NFC rilevati, classifica in modo appropriato i dati e avvia un'applicazione interessata ai dati categorizzati. Un'applicazione che voglia gestire il tag NFC scansionato può dichiarare un filtro per intent e richiedere di gestire i dati.

La funzionalità Android BeamTM consente a un dispositivo di inviare un messaggio NDEF a un altro dispositivo avvicinando fisicamente i dispositivi. Questa interazione offre un modo più semplice per inviare dati rispetto ad altre tecnologie wireless come il Bluetooth, perché con la tecnologia NFC non è necessario effettuare manualmente l'accoppiamento o il rilevamento dei dispositivi. La connessione viene avviata automaticamente quando due dispositivi vengono vicini. Android Beam è disponibile tramite una serie di API NFC, pertanto qualsiasi applicazione può trasmettere informazioni da un dispositivo all'altro. Ad esempio, le applicazioni Contatti, Browser e YouTube utilizzano Android Beam per condividere contatti, pagine web e video con altri dispositivi.

Il sistema di invio dei tag

I dispositivi Android cercano in genere i tag NFC quando lo schermo è sbloccato, a meno che la tecnologia NFC non sia disattivata nel menu Impostazioni del dispositivo. Quando un dispositivo Android rileva un tag NFC, il comportamento desiderato è fare in modo che l'attività più appropriata gestisca l'intento senza chiedere all'utente quale applicazione utilizzare. Poiché i dispositivi analizzano i tag NFC a una distanza molto breve, è probabile che, se si fa selezionare manualmente un'attività, gli utenti li costringono ad allontanare il dispositivo dal tag e a interrompere la connessione. Dovresti sviluppare la tua attività per gestire soltanto i tag NFC che interessano per la tua attività per impedire la visualizzazione del Selettore attività.

Per aiutarti a raggiungere questo obiettivo, Android offre uno speciale sistema di invio dei tag che analizza i tag NFC scansionati, li analizza e tenta di individuare le applicazioni interessate ai dati scansionati. Ecco come:

  1. Analizzare il tag NFC e individuare il tipo MIME o un URI che identifica il payload di dati nel tag.
  2. Incapsulamento del tipo MIME o dell'URI e del payload in un intent. Questi primi due passaggi sono descritti in Modalità di mappatura dei tag NFC a URI e tipi MIME.
  3. Avvia un'attività basata sull'intent. Questa procedura è descritta in Modalità di invio dei tag NFC alle applicazioni.

Modalità di mappatura dei tag NFC ai tipi MIME e agli URI

Prima di iniziare a scrivere le applicazioni NFC, è importante comprendere i diversi tipi di tag NFC, il modo in cui il sistema di invio dei tag analizza i tag NFC e il lavoro speciale svolto dal sistema di invio dei tag quando rileva un messaggio NDEF. I tag NFC sono disponibili in un'ampia gamma di tecnologie e possono anche contenere dati scritti in molti modi diversi. Android ha il supporto maggiore per lo standard NDEF, definito dal Forum NFC.

I dati NDEF vengono incapsulati all'interno di un messaggio (NdefMessage) contenente uno o più record (NdefRecord). Ogni record NDEF deve avere un formato corretto in base alle specifiche del tipo di record che vuoi creare. Android supporta anche altri tipi di tag che non contengono dati NDEF, con i quali puoi lavorare usando le classi nel pacchetto android.nfc.tech. Per scoprire di più su queste tecnologie, consulta l'argomento NFC avanzata. L'utilizzo di questi altri tipi di tag comporta la scrittura di uno stack di protocollo personalizzato per la comunicazione con i tag. Pertanto, quando possibile, consigliamo di utilizzare NDEF per semplificare lo sviluppo e ottenere il massimo supporto per i dispositivi Android.

Nota: per scaricare le specifiche NDEF complete, visita il sito NFC Forum Specifications & Application Documents e vedi Creazione di tipi comuni di record NDEF per esempi su come creare record NDEF.

Ora che hai alcune informazioni sui tag NFC, le sezioni seguenti descrivono in maggiore dettaglio il modo in cui Android gestisce i tag in formato NDEF. Quando un dispositivo Android esegue la scansione di un tag NFC contenente dati in formato NDEF, il messaggio viene analizzato e prova a determinare il tipo MIME o l'URI identificativo dei dati. A questo scopo, il sistema legge il primo NdefRecord all'interno del NdefMessage per determinare come interpretare l'intero messaggio NDEF (un messaggio NDEF può avere più record NDEF). In un messaggio NDEF ben formato, il primo NdefRecord contiene i seguenti campi:

TNF (Type Name Format) a 3 bit
Indica come interpretare il campo del tipo di lunghezza variabile. I valori validi sono descritti nella Tabella 1.
Tipo di lunghezza variabile
Descrive il tipo di record. Se utilizzi TNF_WELL_KNOWN, utilizza questo campo per specificare la definizione del tipo di record (RTD). I valori RTD validi sono descritti nella Tabella 2.
ID lunghezza variabile
Un identificatore univoco del record. Questo campo non viene utilizzato spesso, ma se devi identificare un tag in modo univoco, puoi creare un ID.
Payload a lunghezza variabile
Il payload effettivo che vuoi leggere o scrivere. Un messaggio NDEF può contenere più record NDEF, quindi non dare per scontato che il payload completo si trovi nel primo record NDEF del messaggio NDEF.

Il sistema di invio dei tag utilizza i campi TNF e tipo per provare a mappare un tipo o URI MIME al messaggio NDEF. In caso di esito positivo, incapsula le informazioni all'interno di un intent ACTION_NDEF_DISCOVERED insieme al payload effettivo. Tuttavia, in alcuni casi il sistema di invio dei tag non è in grado di determinare il tipo di dati in base al primo record NDEF. Questo accade quando i dati NDEF non possono essere mappati a un tipo MIME o URI oppure quando il tag NFC non contiene inizialmente dati NDEF. In questi casi, un oggetto Tag che contiene informazioni sulle tecnologie del tag e sul payload viene incapsulato all'interno di un intent ACTION_TECH_DISCOVERED.

La tabella 1 descrive in che modo il sistema di invio dei tag mappa i campi TNF e tipo ai tipi MIME o agli URI. Descrive inoltre quali TNF non possono essere mappati a un tipo MIME o URI. In questi casi, il sistema di invio dei tag torna su ACTION_TECH_DISCOVERED.

Ad esempio, se il sistema di invio dei tag rileva un record di tipo TNF_ABSOLUTE_URI, mappa il campo del tipo di lunghezza variabile di quel record in un URI. Il sistema di invio dei tag incapsula l'URI nel campo dati di un intent ACTION_NDEF_DISCOVERED insieme ad altre informazioni sul tag, come il payload. Se invece rileva un record di tipo TNF_UNKNOWN, crea un intent che invece incapsula le tecnologie del tag.

Tabella 1. TNF supportati e relative mappature

Formato nome del tipo (TNF) Mappatura
TNF_ABSOLUTE_URI URI basato sul campo del tipo.
TNF_EMPTY Torna a ACTION_TECH_DISCOVERED.
TNF_EXTERNAL_TYPE URI basato sull'RNN nel campo type. L'RNN è codificato nel campo di tipo NDEF in una forma abbreviata: <domain_name>:<service_name>. Android lo mappa a un URI nel formato: vnd.android.nfc://ext/<domain_name>:<service_name>.
TNF_MIME_MEDIA Tipo MIME basato sul campo del tipo.
TNF_UNCHANGED Non valido nel primo record, quindi torna a ACTION_TECH_DISCOVERED.
TNF_UNKNOWN Torna a ACTION_TECH_DISCOVERED.
TNF_WELL_KNOWN Tipo MIME o URI in base alla definizione del tipo di record (RTD), impostata nel campo del tipo. Consulta la Tabella 2 per ulteriori informazioni sugli RTD disponibili e sulle relative mappature.

Tabella 2. RTD supportati per TNF_WELL_KNOWN e relative mappature

Definizione del tipo di record (RTD) Mappatura
RTD_ALTERNATIVE_CARRIER Torna a ACTION_TECH_DISCOVERED.
RTD_HANDOVER_CARRIER Torna a ACTION_TECH_DISCOVERED.
RTD_HANDOVER_REQUEST Torna a ACTION_TECH_DISCOVERED.
RTD_HANDOVER_SELECT Torna a ACTION_TECH_DISCOVERED.
RTD_SMART_POSTER URI basato sull'analisi del payload.
RTD_TEXT Tipo MIME di text/plain.
RTD_URI URI basato sul payload.

Modalità di invio dei tag NFC alle applicazioni

Quando il sistema di invio dei tag ha completato la creazione di un intent che incapsula il tag NFC e le relative informazioni di identificazione, invia l'intent a un'applicazione interessata che filtra l'intent. Se più di un'applicazione è in grado di gestire l'intent, viene presentato il Selettore attività in modo che l'utente possa selezionare l'attività. Il sistema di invio dei tag definisce tre intent, elencati in ordine di priorità maggiore o minore:

  1. ACTION_NDEF_DISCOVERED: questo intent viene utilizzato per avviare un'attività quando viene analizzato un tag che contiene un payload NDEF di tipo riconosciuto. Si tratta dell'intent con la massima priorità e il sistema di invio dei tag tenta di avviare un'attività con questo intent prima di qualsiasi altro intent, se possibile.
  2. ACTION_TECH_DISCOVERED: se non viene registrata alcuna attività per gestire l'intent ACTION_NDEF_DISCOVERED, il sistema di invio dei tag tenta di avviare un'applicazione con questo intento. Inoltre, questo intent viene avviato direttamente (senza iniziare prima ACTION_NDEF_DISCOVERED) se il tag sottoposto a scansione contiene dati NDEF che non possono essere mappati a un URI o un tipo MIME oppure se il tag non contiene dati NDEF, ma utilizza una tecnologia di tag nota.
  3. ACTION_TAG_DISCOVERED: questo intent viene avviato se nessuna attività gestisce gli intent ACTION_NDEF_DISCOVERED o ACTION_TECH_DISCOVERED.

Il funzionamento di base del sistema di invio dei tag è il seguente:

  1. Prova ad avviare un'attività con l'intent creato dal sistema di invio dei tag durante l'analisi del tag NFC (ACTION_NDEF_DISCOVERED o ACTION_TECH_DISCOVERED).
  2. Se nessuna attività filtra per quell'intent, prova ad avviare un'attività con l'intent successivo con priorità più bassa (ACTION_TECH_DISCOVERED o ACTION_TAG_DISCOVERED) finché un'applicazione non filtra per l'intent o finché il sistema di invio dei tag non tenta di provare tutti gli intent possibili.
  3. Se nessuna applicazione filtra gli intent, non fare nulla.
Figura 1. Sistema di invio dei tag

Quando possibile, utilizza i messaggi NDEF e l'intent ACTION_NDEF_DISCOVERED, perché è il più specifico dei tre. Questo intent ti consente di avviare la tua applicazione in un momento più appropriato rispetto agli altri due intent, offrendo all'utente un'esperienza migliore.

Richiedere l'accesso a NFC nel file manifest Android

Per poter accedere all'hardware NFC di un dispositivo e gestire correttamente gli intent NFC, dichiara questi elementi nel file AndroidManifest.xml:

  • L'elemento <uses-permission> NFC per accedere all'hardware NFC:
    <uses-permission android:name="android.permission.NFC" />
    
  • La versione minima dell'SDK che la tua applicazione può supportare. Il livello API 9 supporta solo l'invio di tag limitati tramite ACTION_TAG_DISCOVERED e concede l'accesso solo ai messaggi NDEF tramite il EXTRA_NDEF_MESSAGES extra. Non sono accessibili altre proprietà dei tag o operazioni di I/O. Il livello API 10 include un supporto completo per lettori/autori e il push NDEF in primo piano, mentre il livello API 14 offre un modo più semplice per inviare messaggi NDEF ad altri dispositivi con Android Beam e metodi aggiuntivi per creare record NDEF.
    <uses-sdk android:minSdkVersion="10"/>
    
  • L'elemento uses-feature per fare in modo che la tua applicazione venga visualizzata in Google Play solo per i dispositivi con hardware NFC:
    <uses-feature android:name="android.hardware.nfc" android:required="true" />
    

    Se la tua applicazione utilizza la funzionalità NFC, ma questa funzionalità non è fondamentale per la tua applicazione, puoi omettere l'elemento uses-feature e verificare la disponibilità NFC in tempo di esecuzione verificando se getDefaultAdapter() è null.

Filtra per intent NFC

Per avviare l'applicazione quando viene scansionato un tag NFC che vuoi gestire, l'applicazione può filtrare uno, due o tutti e tre gli intent NFC nel file manifest Android. Tuttavia, di solito conviene filtrare in base all'intent ACTION_NDEF_DISCOVERED per avere il massimo controllo sull'avvio dell'applicazione. L'intent ACTION_TECH_DISCOVERED è un fallback per ACTION_NDEF_DISCOVERED quando nessuna applicazione filtra per ACTION_NDEF_DISCOVERED o per quando il payload non è NDEF. In genere, l'applicazione di filtri per ACTION_TAG_DISCOVERED è troppo generica per una categoria in base al quale applicare un filtro. Molte applicazioni filtreranno per ACTION_NDEF_DISCOVERED o ACTION_TECH_DISCOVERED prima del giorno ACTION_TAG_DISCOVERED, quindi è poco probabile che l'applicazione venga avviata. ACTION_TAG_DISCOVERED è disponibile solo come ultima risorsa per applicare filtri alle applicazioni nei casi in cui non siano installate altre applicazioni per gestire l'intent ACTION_NDEF_DISCOVERED o ACTION_TECH_DISCOVERED.

Poiché i deployment dei tag NFC variano e molte volte non sono sotto il tuo controllo, non è sempre possibile, motivo per cui, se necessario, puoi ricorrere agli altri due intent. Una volta controllato i tipi di tag e i dati scritti, consigliamo di utilizzare NDEF per formattare i tag. Le seguenti sezioni descrivono come filtrare per ogni tipo di intent.

ACTION_NDEF_DISCOVERED

Per filtrare in base agli intent ACTION_NDEF_DISCOVERED, dichiara il filtro per intent insieme al tipo di dati per cui vuoi filtrare. Il seguente esempio filtra per gli intent ACTION_NDEF_DISCOVERED con un tipo MIME text/plain:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="text/plain" />
</intent-filter>

L'esempio seguente filtra per un URI nel formato https://developer.android.com/index.html.

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
   <data android:scheme="https"
              android:host="developer.android.com"
              android:pathPrefix="/index.html" />
</intent-filter>

ACTION_TECH_SCOPERTA

Se l'attività filtra per l'intent ACTION_TECH_DISCOVERED, devi creare un file di risorse XML che specifichi le tecnologie supportate dalla tua attività all'interno di un set di tech-list. La tua attività viene considerata una corrispondenza se un set tech-list è un sottoinsieme delle tecnologie supportate dal tag, che puoi ottenere chiamando getTechList().

Ad esempio, se il tag scansionato supporta MifareClassic, NdefFormatable e NfcA, il tuo set tech-list deve specificare tutte e tre le tecnologie (e nient'altra) per trovare corrispondenze con la tua attività.

L'esempio seguente definisce tutte le tecnologie. Devi rimuovere quelle non supportate dal tag NFC. Salva questo file (puoi assegnargli il nome che preferisci) nella cartella <project-root>/res/xml.

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.IsoDep</tech>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.NfcB</tech>
        <tech>android.nfc.tech.NfcF</tech>
        <tech>android.nfc.tech.NfcV</tech>
        <tech>android.nfc.tech.Ndef</tech>
        <tech>android.nfc.tech.NdefFormatable</tech>
        <tech>android.nfc.tech.MifareClassic</tech>
        <tech>android.nfc.tech.MifareUltralight</tech>
    </tech-list>
</resources>

Puoi anche specificare più insiemi di tech-list. Ciascuno dei set tech-list viene considerato in modo indipendente e la tua attività viene considerata una corrispondenza se ogni singolo insieme tech-list è un sottoinsieme delle tecnologie restituite da getTechList(). Fornisce la semantica AND e OR per le tecnologie di corrispondenza. L'esempio seguente corrisponde a tag che supportano le tecnologie NfcA e Ndef o che supportano le tecnologie NfcB e Ndef:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcB</tech>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
</resources>

Nel tuo file AndroidManifest.xml, specifica il file di risorsa appena creato nell'elemento <meta-data> all'interno dell'elemento <activity> come nell'esempio seguente:

<activity>
...
<intent-filter>
    <action android:name="android.nfc.action.TECH_DISCOVERED"/>
</intent-filter>

<meta-data android:name="android.nfc.action.TECH_DISCOVERED"
    android:resource="@xml/nfc_tech_filter" />
...
</activity>

Per ulteriori informazioni sull'utilizzo delle tecnologie di tag e dell'intent ACTION_TECH_DISCOVERED, consulta Utilizzo delle tecnologie di tag supportate nel documento NFC avanzato.

ACTION_TAG_SCOPERTA

Per filtrare per ACTION_TAG_DISCOVERED, utilizza il seguente filtro per intent:

<intent-filter>
    <action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>

Ottenere informazioni dagli intent

Se un'attività inizia a causa di un intent NFC, puoi ottenere informazioni sul tag NFC scansionato dall'intent. Gli intent possono contenere i seguenti extra, a seconda del tag sottoposto a scansione:

Per ottenere queste funzionalità aggiuntive, controlla se la tua attività è stata avviata con uno degli intent NFC per assicurarti che un tag sia stato scansionato, quindi estrai le informazioni aggiuntive dall'intent. L'esempio seguente verifica l'intent ACTION_NDEF_DISCOVERED e recupera i messaggi NDEF da un intent aggiuntivo.

Kotlin

override fun onNewIntent(intent: Intent) {
    super.onNewIntent(intent)
    ...
    if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
        intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMessages ->
            val messages: List<NdefMessage> = rawMessages.map { it as NdefMessage }
            // Process the messages array.
            ...
        }
    }
}

Java

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    ...
    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
        Parcelable[] rawMessages =
            intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
        if (rawMessages != null) {
            NdefMessage[] messages = new NdefMessage[rawMessages.length];
            for (int i = 0; i < rawMessages.length; i++) {
                messages[i] = (NdefMessage) rawMessages[i];
            }
            // Process the messages array.
            ...
        }
    }
}

In alternativa, puoi ottenere un oggetto Tag dall'intent, che conterrà il payload e ti consentirà di enumerare le tecnologie del tag:

Kotlin

val tag: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)

Java

Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

Creare tipi comuni di record NDEF

Questa sezione descrive come creare tipi comuni di record NDEF per semplificare la scrittura sui tag NFC o l'invio di dati con Android Beam. A partire da Android 4.0 (livello API 14), il metodo createUri() è disponibile per aiutarti a creare automaticamente record URI. A partire da Android 4.1 (livello API 16), createExternal() e createMime() sono disponibili per aiutarti a creare record MIME e NDEF di tipo esterno. Se possibile, utilizza questi metodi di supporto per evitare errori durante la creazione manuale dei record NDEF.

In questa sezione viene inoltre descritto come creare il filtro per intent corrispondente per il record. Tutti questi esempi di record NDEF devono essere nel primo record NDEF del messaggio NDEF che stai scrivendo in un tag o beaming.

TNF_ABSOLUTE_URI

Nota: ti consigliamo di utilizzare il tipo RTD_URI anziché TNF_ABSOLUTE_URI, perché è più efficiente.

Puoi creare un record NDEF TNF_ABSOLUTE_URI nel seguente modo:

Kotlin

val uriRecord = ByteArray(0).let { emptyByteArray ->
    NdefRecord(
            TNF_ABSOLUTE_URI,
            "https://developer.android.com/index.html".toByteArray(Charset.forName("US-ASCII")),
            emptyByteArray,
            emptyByteArray
    )
}

Java

NdefRecord uriRecord = new NdefRecord(
    NdefRecord.TNF_ABSOLUTE_URI ,
    "https://developer.android.com/index.html".getBytes(Charset.forName("US-ASCII")),
    new byte[0], new byte[0]);

Il filtro per intent per il record NDEF precedente avrebbe il seguente aspetto:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="https"
        android:host="developer.android.com"
        android:pathPrefix="/index.html" />
</intent-filter>

TNF_MIME_MEDIA

Puoi creare un record NDEF TNF_MIME_MEDIA nei seguenti modi:

Con il metodo createMime():

Kotlin

val mimeRecord = NdefRecord.createMime(
        "application/vnd.com.example.android.beam",
        "Beam me up, Android".toByteArray(Charset.forName("US-ASCII"))
)

Java

NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam",
    "Beam me up, Android".getBytes(Charset.forName("US-ASCII")));

Creazione manuale di NdefRecord:

Kotlin

val mimeRecord = Charset.forName("US-ASCII").let { usAscii ->
    NdefRecord(
            NdefRecord.TNF_MIME_MEDIA,
            "application/vnd.com.example.android.beam".toByteArray(usAscii),
            ByteArray(0),
            "Beam me up, Android!".toByteArray(usAscii)
    )
}

Java

NdefRecord mimeRecord = new NdefRecord(
    NdefRecord.TNF_MIME_MEDIA ,
    "application/vnd.com.example.android.beam".getBytes(Charset.forName("US-ASCII")),
    new byte[0], "Beam me up, Android!".getBytes(Charset.forName("US-ASCII")));

Il filtro per intent per il record NDEF precedente avrebbe il seguente aspetto:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="application/vnd.com.example.android.beam" />
</intent-filter>

TNF_WELL_KNOWN con RTD_TEXT

Puoi creare un record NDEF TNF_WELL_KNOWN nel seguente modo:

Kotlin

fun createTextRecord(payload: String, locale: Locale, encodeInUtf8: Boolean): NdefRecord {
    val langBytes = locale.language.toByteArray(Charset.forName("US-ASCII"))
    val utfEncoding = if (encodeInUtf8) Charset.forName("UTF-8") else Charset.forName("UTF-16")
    val textBytes = payload.toByteArray(utfEncoding)
    val utfBit: Int = if (encodeInUtf8) 0 else 1 shl 7
    val status = (utfBit + langBytes.size).toChar()
    val data = ByteArray(1 + langBytes.size + textBytes.size)
    data[0] = status.toByte()
    System.arraycopy(langBytes, 0, data, 1, langBytes.size)
    System.arraycopy(textBytes, 0, data, 1 + langBytes.size, textBytes.size)
    return NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, ByteArray(0), data)
}

Java

public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
    byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
    Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
    byte[] textBytes = payload.getBytes(utfEncoding);
    int utfBit = encodeInUtf8 ? 0 : (1 << 7);
    char status = (char) (utfBit + langBytes.length);
    byte[] data = new byte[1 + langBytes.length + textBytes.length];
    data[0] = (byte) status;
    System.arraycopy(langBytes, 0, data, 1, langBytes.length);
    System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
    NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
    NdefRecord.RTD_TEXT, new byte[0], data);
    return record;
}

Il filtro per intent per il record NDEF precedente avrebbe il seguente aspetto:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:mimeType="text/plain" />
</intent-filter>

TNF_WELL_KNOWN con RTD_URI

Puoi creare un record NDEF TNF_WELL_KNOWN nei seguenti modi:

Con il metodo createUri(String):

Kotlin

val rtdUriRecord1 = NdefRecord.createUri("https://example.com")

Java

NdefRecord rtdUriRecord1 = NdefRecord.createUri("https://example.com");

Con il metodo createUri(Uri):

Kotlin

val rtdUriRecord2 = Uri.parse("https://example.com").let { uri ->
    NdefRecord.createUri(uri)
}

Java

Uri uri = Uri.parse("https://example.com");
NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);

Creazione manuale di NdefRecord:

Kotlin

val uriField = "example.com".toByteArray(Charset.forName("US-ASCII"))
val payload = ByteArray(uriField.size + 1)                   //add 1 for the URI Prefix
payload [0] = 0x01                                           //prefixes https://www. to the URI
System.arraycopy(uriField, 0, payload, 1, uriField.size)     //appends URI to payload
val rtdUriRecord = NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, ByteArray(0), payload)

Java

byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII"));
byte[] payload = new byte[uriField.length + 1];              //add 1 for the URI Prefix
payload[0] = 0x01;                                           //prefixes https://www. to the URI
System.arraycopy(uriField, 0, payload, 1, uriField.length);  //appends URI to payload
NdefRecord rtdUriRecord = new NdefRecord(
    NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);

Il filtro per intent per il record NDEF precedente avrebbe il seguente aspetto:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="https"
        android:host="example.com"
        android:pathPrefix="" />
</intent-filter>

TNF_EXTERNAL_TYPE

Puoi creare un record NDEF TNF_EXTERNAL_TYPE nei seguenti modi:

Con il metodo createExternal():

Kotlin

var payload: ByteArray //assign to your data
val domain = "com.example" //usually your app's package name
val type = "externalType"
val extRecord = NdefRecord.createExternal(domain, type, payload)

Java

byte[] payload; //assign to your data
String domain = "com.example"; //usually your app's package name
String type = "externalType";
NdefRecord extRecord = NdefRecord.createExternal(domain, type, payload);

Creazione manuale di NdefRecord:

Kotlin

var payload: ByteArray
...
val extRecord = NdefRecord(
        NdefRecord.TNF_EXTERNAL_TYPE,
        "com.example:externalType".toByteArray(Charset.forName("US-ASCII")),
        ByteArray(0),
        payload
)

Java

byte[] payload;
...
NdefRecord extRecord = new NdefRecord(
    NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType".getBytes(Charset.forName("US-ASCII")),
    new byte[0], payload);

Il filtro per intent per il record NDEF precedente avrebbe il seguente aspetto:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />
    <data android:scheme="vnd.android.nfc"
        android:host="ext"
        android:pathPrefix="/com.example:externalType"/>
</intent-filter>

Utilizza TNF_EXTERNAL_TYPE per implementazioni di tag NFC più generiche al fine di supportare meglio i dispositivi Android e non.

Nota: gli URN per TNF_EXTERNAL_TYPE hanno un formato canonico urn:nfc:ext:example.com:externalType, tuttavia la specifica RTD del Forum NFC dichiara che la porzione urn:nfc:ext: dell'RNN deve essere omessa dal record NDEF. Devi solo fornire il dominio (example.com nell'esempio) e il tipo (externalType nell'esempio) separati dai due punti. Quando invii TNF_EXTERNAL_TYPE, Android converte l'URN urn:nfc:ext:example.com:externalType in un URI vnd.android.nfc://ext/example.com:externalType, che è ciò che dichiara il filtro per intent nell'esempio.

Record di app per Android

Introdotto in Android 4.0 (livello API 14), un record dell'applicazione Android (AAR) offre una maggiore certezza che l'applicazione viene avviata quando viene eseguita la scansione di un tag NFC. Un AAR ha il nome del pacchetto di un'applicazione incorporata in un record NDEF. Puoi aggiungere un AAR a qualsiasi record NDEF del tuo messaggio NDEF, perché Android cerca gli AAR nell'intero messaggio NDEF. Se trova un AAR, avvia l'applicazione in base al nome del pacchetto all'interno dell'AAR. Se l'applicazione non è presente sul dispositivo, viene avviato Google Play per scaricare l'applicazione.

Gli AAR sono utili se vuoi impedire ad altre applicazioni di filtrare in base allo stesso intent e gestire potenzialmente tag specifici di cui hai eseguito il deployment. Gli AAR sono supportati solo a livello di applicazione, per via del vincolo del nome del pacchetto, e non a livello di attività come con il filtro dell'intent. Se vuoi gestire un intent a livello di attività, utilizza i filtri per intent.

Se un tag contiene un AAR, il sistema di invio dei tag esegue l'invio nel seguente modo:

  1. Prova ad avviare un'attività utilizzando un filtro per intent come di consueto. Se l'attività che corrisponde all'intent corrisponde anche all'AAR, avvia l'attività.
  2. Se l'attività che filtra per l'intent non corrisponde all'AAR, se più attività possono gestire l'intent o se nessuna attività gestisce l'intent, avvia l'applicazione specificata dall'AAR.
  3. Se nessuna applicazione può essere avviata con questo programma, accedi a Google Play per scaricare l'applicazione in base a questo certificato.

Nota:puoi sostituire gli AAR e il sistema di invio degli intent con il sistema di invio in primo piano, che consente a un'attività in primo piano di avere la priorità quando viene rilevato un tag NFC. Con questo metodo, l'attività deve essere in primo piano per sostituire gli AAR e il sistema di invio degli intent.

Se vuoi comunque filtrare i tag analizzati che non contengono un AAR, puoi dichiarare i filtri intent come di consueto. Questo è utile se la tua applicazione è interessata ad altri tag che non contengono un AAR. Ad esempio, potresti voler assicurare che la tua applicazione gestisca i tag proprietari di cui hai eseguito il deployment e i tag generali implementati da terze parti. Tieni presente che gli AAR sono specifici dei dispositivi Android 4.0 o versioni successive. Di conseguenza, quando esegui il deployment dei tag, è molto probabile che tu voglia utilizzare una combinazione di AAR e tipi MIME/URI per supportare la più ampia gamma di dispositivi. Inoltre, quando implementi i tag NFC, pensa a come desideri scrivere i tag NFC per abilitare il supporto per la maggior parte dei dispositivi (Android e di altro tipo). Puoi farlo definendo un tipo MIME o URI relativamente unico per facilitare la distinzione delle applicazioni.

Android offre una semplice API per creare un AAR, createApplicationRecord(). Devi solo incorporare l'AAR in qualsiasi punto di NdefMessage. Non vuoi usare il primo record del tuo NdefMessage, a meno che l'AAR non sia l'unico record in NdefMessage. Questo perché il sistema Android controlla il primo record di un codice NdefMessage per determinare il tipo MIME o URI del tag, che viene utilizzato per creare un intent che consenta alle applicazioni di filtrare. Il seguente codice mostra come creare un AAR:

Kotlin

val msg = NdefMessage(
        arrayOf(
                ...,
                NdefRecord.createApplicationRecord("com.example.android.beam")
        )
)

Java

NdefMessage msg = new NdefMessage(
        new NdefRecord[] {
            ...,
            NdefRecord.createApplicationRecord("com.example.android.beam")}
        );
)

Trasmetti messaggi NDEF ad altri dispositivi

Android Beam consente uno scambio di dati peer-to-peer semplice tra due dispositivi Android. L'applicazione che vuole trasmettere dati a un altro dispositivo deve essere in primo piano e il dispositivo che riceve i dati non deve essere bloccato. Quando il dispositivo di trasmissione entra in contatto abbastanza ravvicinato con un dispositivo ricevente, quest'ultimo mostra l'interfaccia utente "Tocca per trasmettere". L'utente può quindi scegliere se trasmettere o meno il messaggio al dispositivo ricevente.

Nota: il push NDEF in primo piano era disponibile al livello API 10, che fornisce una funzionalità simile ad Android Beam. Queste API sono state ritirate, ma sono disponibili per supportare i dispositivi meno recenti. Leggi i enableForegroundNdefPush() per avere ulteriori informazioni.

Puoi attivare Android Beam per la tua applicazione chiamando uno dei due metodi seguenti:

  • setNdefPushMessage(): accetta un NdefMessage da impostare come messaggio da trasmettere. Il messaggio viene trasmesso automaticamente quando due dispositivi si trovano nelle vicinanze.
  • setNdefPushMessageCallback(): accetta un callback che contiene un createNdefMessage() che viene chiamato quando un dispositivo è nel raggio d'azione per trasmettere i dati. Il callback consente di creare il messaggio NDEF solo quando necessario.

Un'attività può eseguire il push di un solo messaggio NDEF alla volta, quindi setNdefPushMessageCallback() ha la precedenza su setNdefPushMessage() se sono impostati entrambi. Per utilizzare Android Beam, devono essere rispettate le seguenti linee guida generali:

  • L'attività che trasmette i dati deve essere in primo piano. Entrambi i dispositivi devono avere lo schermo sbloccato.
  • Devi incapsulare i dati che stai trasmettendo in un oggetto NdefMessage.
  • Il dispositivo NFC che riceve i dati trasmessi deve supportare il protocollo push com.android.npp NDEF o il protocollo SNEP (Simple NDEF Exchange Protocol) dell'NFC Forum. Il protocollo com.android.npp è obbligatorio per i dispositivi dal livello API 9 (Android 2.3) al livello API 13 (Android 3.2). com.android.npp e SNEP sono entrambi obbligatori a livello API 14 (Android 4.0) e versioni successive.

Nota: se la tua attività attiva Android Beam ed è in primo piano, il sistema di invio degli intent standard è disattivato. Tuttavia, se l'attività attiva anche l' invio in primo piano, potrà comunque analizzare i tag che corrispondono ai filtri per intent impostati nell'invio in primo piano.

Per attivare Android Beam:

  1. Crea un elemento NdefMessage contenente i NdefRecord di cui vuoi eseguire il push all'altro dispositivo.
  2. Richiama setNdefPushMessage() con un NdefMessage o chiama setNdefPushMessageCallback passando in un oggetto NfcAdapter.CreateNdefMessageCallback nel metodo onCreate() della tua attività. Questi metodi richiedono almeno un'attività che vuoi attivare con Android Beam, oltre a un elenco facoltativo di altre attività da attivare.

    In generale, usi setNdefPushMessage() se la tua attività deve inviare sempre lo stesso messaggio NDEF quando due dispositivi sono vicini per comunicare. Utilizzi setNdefPushMessageCallback quando la tua applicazione è interessata al contesto corrente dell'applicazione e vuole inviare un messaggio NDEF a seconda di ciò che sta facendo l'utente nell'applicazione.

Il seguente esempio mostra come una semplice attività chiama NfcAdapter.CreateNdefMessageCallback nel metodo onCreate() di un'attività (consulta AndroidBeamDemo per l'esempio completo). Questo esempio include anche metodi per aiutarti a creare un record MIME:

Kotlin

package com.example.android.beam

import android.app.Activity
import android.content.Intent
import android.nfc.NdefMessage
import android.nfc.NdefRecord
import android.nfc.NfcAdapter
import android.nfc.NfcAdapter.CreateNdefMessageCallback
import android.nfc.NfcEvent
import android.os.Bundle
import android.os.Parcelable
import android.widget.TextView
import android.widget.Toast
import java.nio.charset.Charset

class Beam : Activity(), NfcAdapter.CreateNdefMessageCallback {
    
    private var nfcAdapter: NfcAdapter? = null
    private lateinit var textView: TextView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main)
        textView = findViewById(R.id.textView)
        // Check for available NFC Adapter
        nfcAdapter = NfcAdapter.getDefaultAdapter(this)
        if (nfcAdapter == null) {
            Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show()
            finish()
            return
        }
        // Register callback
        nfcAdapter?.setNdefPushMessageCallback(this, this)
    }

    override fun createNdefMessage(event: NfcEvent): NdefMessage {
        val text = "Beam me up, Android!\n\n" +
                "Beam Time: " + System.currentTimeMillis()
        return NdefMessage(
                arrayOf(
                        createMime("application/vnd.com.example.android.beam", text.toByteArray())
                )
                /**
                 * The Android Application Record (AAR) is commented out. When a device
                 * receives a push with an AAR in it, the application specified in the AAR
                 * is guaranteed to run. The AAR overrides the tag dispatch system.
                 * You can add it back in to guarantee that this
                 * activity starts when receiving a beamed message. For now, this code
                 * uses the tag dispatch system.
                 *///,NdefRecord.createApplicationRecord("com.example.android.beam")
        )
    }

    override fun onResume() {
        super.onResume()
        // Check to see that the Activity started due to an Android Beam
        if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
            processIntent(intent)
        }
    }

    override fun onNewIntent(intent: Intent) {
        // onResume gets called after this to handle the intent
        setIntent(intent)
    }

    /**
     * Parses the NDEF Message from the intent and prints to the TextView
     */
    private fun processIntent(intent: Intent) {
        textView = findViewById(R.id.textView)
        // only one message sent during the beam
        intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMsgs ->
            (rawMsgs[0] as NdefMessage).apply {
                // record 0 contains the MIME type, record 1 is the AAR, if present
                textView.text = String(records[0].payload)
            }
        }
    }
}

Java

package com.example.android.beam;

import android.app.Activity;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.os.Parcelable;
import android.widget.TextView;
import android.widget.Toast;
import java.nio.charset.Charset;


public class Beam extends Activity implements CreateNdefMessageCallback {
    NfcAdapter nfcAdapter;
    TextView textView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TextView textView = (TextView) findViewById(R.id.textView);
        // Check for available NFC Adapter
        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (nfcAdapter == null) {
            Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
            finish();
            return;
        }
        // Register callback
        nfcAdapter.setNdefPushMessageCallback(this, this);
    }

    @Override
    public NdefMessage createNdefMessage(NfcEvent event) {
        String text = ("Beam me up, Android!\n\n" +
                "Beam Time: " + System.currentTimeMillis());
        NdefMessage msg = new NdefMessage(
                new NdefRecord[] { createMime(
                        "application/vnd.com.example.android.beam", text.getBytes())
         /**
          * The Android Application Record (AAR) is commented out. When a device
          * receives a push with an AAR in it, the application specified in the AAR
          * is guaranteed to run. The AAR overrides the tag dispatch system.
          * You can add it back in to guarantee that this
          * activity starts when receiving a beamed message. For now, this code
          * uses the tag dispatch system.
          */
          //,NdefRecord.createApplicationRecord("com.example.android.beam")
        });
        return msg;
    }

    @Override
    public void onResume() {
        super.onResume();
        // Check to see that the Activity started due to an Android Beam
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
            processIntent(getIntent());
        }
    }

    @Override
    public void onNewIntent(Intent intent) {
        // onResume gets called after this to handle the intent
        setIntent(intent);
    }

    /**
     * Parses the NDEF Message from the intent and prints to the TextView
     */
    void processIntent(Intent intent) {
        textView = (TextView) findViewById(R.id.textView);
        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
                NfcAdapter.EXTRA_NDEF_MESSAGES);
        // only one message sent during the beam
        NdefMessage msg = (NdefMessage) rawMsgs[0];
        // record 0 contains the MIME type, record 1 is the AAR, if present
        textView.setText(new String(msg.getRecords()[0].getPayload()));
    }
}

Tieni presente che questo codice commenta un AAR, che puoi rimuovere. Se abiliti l'AAR, l'applicazione specificata nell'AAR riceve sempre il messaggio Android Beam. Se l'applicazione non è presente, Google Play inizia a scaricarla. Pertanto, il seguente filtro per intent non è tecnicamente necessario per i dispositivi Android 4.0 o versioni successive se viene utilizzato l'AAR:

<intent-filter>
  <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <data android:mimeType="application/vnd.com.example.android.beam"/>
</intent-filter>

Con questo filtro per intent, l'applicazione com.example.android.beam ora può essere avviata quando analizza un tag NFC o riceve un Android Beam con un AAR di tipo com.example.android.beam oppure quando un messaggio in formato NDEF contiene un record MIME di tipo application/vnd.com.example.android.beam.

Anche se gli AAR garantiscono che un'applicazione viene avviata o scaricata, consigliamo di utilizzare i filtri per intent, perché consentono di avviare un'attività scelta da te nell'applicazione anziché avviare sempre l'attività principale all'interno del pacchetto specificato da un AAR. Gli AAR non hanno granularità a livello di attività. Inoltre, poiché alcuni dispositivi Android non supportano gli AAR, devi incorporare anche le informazioni di identificazione nel primo record NDEF dei messaggi NDEF e applicare un filtro anche per queste, per sicurezza. Consulta Creazione di tipi comuni di record NDEF per ulteriori informazioni su come creare record.