Läser NFC-taggar med Android

Är du nyfiken på vad NFC är och hur det kan integreras i dina egna Android-applikationer? Denna handledning introducerar dig snabbt till ämnet innan du dyker i och lär dig hur man bygger en enkel NFC-läsareapp!


Vad är NFC?

NFC är förkortningen för Nära fältkommunikation. Det är den internationella standarden för kontaktlös datautbyte. Till skillnad från ett stort antal andra tekniker, som trådlöst LAN och Bluetooth, är det maximala avståndet för två enheter 10 cm. Utvecklingen av standarden startade 2002 av NXP Semiconductors och Sony. NFC Forum, ett konsortium på över 170 företag och medlemmar, inklusive Mastercard, NXP, Nokia, Samsung, Intel och Google, har utformat nya specifikationer sedan 2004.

Det finns olika möjligheter för NFC-användning med mobila enheter. till exempel papperslösa biljetter, åtkomstkontroller, kontantlösa betalningar och bilnycklar. Med hjälp av NFC-taggar kan du styra din telefon och ändra inställningar. Data kan bytas enkelt genom att hålla två enheter bredvid varandra.

I denna handledning vill jag förklara hur man implementerar NFC med Android SDK, vilka fallgropar finns och vad man ska komma ihåg. Vi kommer att skapa en app steg för steg, som kan läsa innehållet i NFC-taggar som stöder NDEF.


NFC Technologies

Det finns en mängd NFC-taggar som kan läsas med en smartphone. Spektret sträcker sig från enkla klistermärken och nyckelringar till komplexa kort med integrerad kryptografisk maskinvara. Taggar skiljer sig också åt i sin chipteknik. Det viktigaste är NDEF, som stöds av de flesta taggar. I tillägg bör Mifare nämnas eftersom det är den mest använda kontaktlösa chipteknologin världen över. Vissa taggar kan läsas och skrivas, medan andra är skrivskyddade eller krypterade.

Endast NFAF-datautbytesformatet (NDEF) diskuteras i denna handledning.


Lägga till NFC-support i en app

Vi börjar med ett nytt projekt och en tom aktivitet. Det är viktigt att välja en minsta SDK-version av nivå 10, eftersom NFC endast stöds efter Android 2.3.3. Kom ihåg att välja ditt eget paketnamn. jag har valt net.vrallev.android.nfc.demo, eftersom vrallev.net är domänen på min hemsida och den andra delen avser ämnet för denna ansökan.

 

Standardlayouten som genereras av Eclipse är nästan tillräcklig för oss. Jag har bara lagt till ett ID till TextView och ändrat texten.

 

För att få tillgång till NFC-hårdvaran måste du ansöka om tillstånd i manifestet. Om appen inte fungerar utan NFC kan du ange villkoret med användningsfunktionstaggen. Om NFC krävs kan appen inte installeras på enheter utan den och Google Play visar bara din app till användare som äger en NFC-enhet.

  

MainActivity ska endast bestå av metoden onCreate (). Du kan interagera med hårdvaran via NfcAdapter-klassen. Det är viktigt att ta reda på om NfcAdapter är null. I det här fallet stödjer Android-enheten inte NFC.

 paketet net.vrallev.android.nfc.demo; importera android.app.Activity; importera android.nfc.NfcAdapter; importera android.os.Bundle; importera android.widget.TextView; importera android.widget.Toast; / ** * Aktivitet för att läsa data från en NDEF-tagg. * * @author Ralf Wondratschek * * / public class MainActivity utökar aktivitet public static static string TAG = "NfcDemo"; privat textvy mTextView; privat NfcAdapter mNfcAdapter; @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); mTextView = (TextView) findViewById (R.id.textView_explanation); mNfcAdapter = NfcAdapter.getDefaultAdapter (detta); om (mNfcAdapter == null) // Stanna här, vi behöver definitivt NFC Toast.makeText (detta "Denna enhet stöder inte NFC.", Toast.LENGTH_LONG) .show (); Avsluta(); lämna tillbaka;  om (! mNfcAdapter.isEnabled ()) mTextView.setText ("NFC är inaktiverad.");  annars mTextView.setText (R.string.explanation);  handleIntent (getIntent ());  privat tomt handtagIntent (Intent Intent) // TODO: hantera Intent

Om vi ​​startar vår app nu kan vi se texten om NFC är aktiverat eller inaktiverat.

Hur man filtrerar för NFC-taggar

Vi har vår provapp och vill få en anmälan från systemet när vi bifogar en NFC-tagg till enheten. Som vanligt använder Android sitt Intent-system för att leverera taggar till appar. Om flera appar kan hantera avsiktet visas aktivitetsväljaren och användaren kan bestämma vilken app som ska öppnas. Öppna webbadresser eller dela information hanteras på samma sätt.


NFC Intent Filter

Det finns tre olika filter för taggar:

  1. ACTION_NDEF_DISCOVERED
  2. ACTION_TECH_DISCOVERED
  3. ACTION_TAG_DISCOVERED

Listan sorteras från högsta till lägsta prioritet.

Vad händer nu när en tagg är ansluten till smartphone? Om systemet upptäcker en tagg med NDEF-stöd, utlöses en Intent. En ACTION_TECH_DISCOVERED Intent utlöses om ingen aktivitet från någon app är registrerad för NDEF Intent eller om taggen inte stöder NDEF. Om det inte hittas någon app för Intent eller om chip-tekniken inte kunde detekteras, så a ACTION_TAG_DISCOVERED Avsikten är avfyrade. Följande grafik visar processen:


Sammanfattningsvis innebär det att varje app måste filtrera efter Intent med högsta prioritet. I vårt fall är detta NDEF Intent. Vi implementerar ACTION_TECH_DISCOVERED Avsikten är först att markera skillnaden mellan prioriteringar.


Tech Upptäckt Intent

Vi måste ange vilken teknik vi är intresserade av. För detta ändamål skapar vi en undermapp som heter xml i res mapp. I den här mappen skapar vi filen nfc_tech_filter.xml, där vi specificerar tekniken.

    android.nfc.tech.Ndef    

Nu måste vi skapa en IntentFilter i manifestet, och appen kommer att startas när vi bifogar en tagg.

           

Om ingen annan app är registrerad för denna Intent startar vår aktivitet omedelbart. På min enhet installeras dock andra appar, så aktivitetsväljaren visas.



NDEF Upptäckt Intent

Som jag nämnde tidigare har Tech Discovered Intent den näst högsta prioriteten. Eftersom vår app bara stöder NDEF kan vi dock använda NDEF Discovered Intent, vilket har högre prioritet. Vi kan ta bort tekniklistan igen och ersätta IntentFilter med följande.

     

När vi bifogar taggen nu startas appen som tidigare. Det är dock en skillnad för mig. Aktivitetsväljaren visas inte och appen startas omedelbart, eftersom NDEF-avsikten har högre prioritet och de andra programmen endast registreras för de lägre prioriteringarna. Det är precis vad vi vill ha.


Förutsändning

Observera att ett problem kvarstår. När vår app redan är öppen och vi bifogar taggen igen öppnas appen en andra gång istället för att leverera taggen direkt. Detta är inte vårt avsedda beteende. Du kan kringgå problemet genom att använda en förgrundsleverans.

I stället för att systemet har distribuerat Intent kan du registrera din aktivitet för att få taggen direkt. Detta är viktigt för ett visst arbetsflöde, där det inte är meningslöst att öppna en annan app.

Jag har lagt in förklaringarna på lämpliga platser i koden.

 paketet net.vrallev.android.nfc.demo; importera android.app.Activity; importera android.app.PendingIntent; importera android.content.Intent; importera android.content.IntentFilter; importera android.content.IntentFilter.MalformedMimeTypeException; importera android.nfc.NfcAdapter; importera android.os.Bundle; importera android.widget.TextView; importera android.widget.Toast; / ** * Aktivitet för att läsa data från en NDEF-tagg. * * @author Ralf Wondratschek * * / public class MainActivity utökar aktivitet public static final string MIME_TEXT_PLAIN = "text / plain"; offentlig statisk slutsträng TAG = "NfcDemo"; privat textvy mTextView; privat NfcAdapter mNfcAdapter; @Override protected void onCreate (Bundle savedInstanceState) super.onCreate (savedInstanceState); setContentView (R.layout.activity_main); mTextView = (TextView) findViewById (R.id.textView_explanation); mNfcAdapter = NfcAdapter.getDefaultAdapter (detta); om (mNfcAdapter == null) // Stanna här, vi behöver definitivt NFC Toast.makeText (detta "Denna enhet stöder inte NFC.", Toast.LENGTH_LONG) .show (); Avsluta(); lämna tillbaka;  om (! mNfcAdapter.isEnabled ()) mTextView.setText ("NFC är inaktiverad.");  annars mTextView.setText (R.string.explanation);  handleIntent (getIntent ());  @Override protected void onResume () super.onResume (); / ** * Det är viktigt att aktiviteten är i förgrunden (återupptagen). Annars kastas en IllegalStateException. * / setupForegroundDispatch (detta, mNfcAdapter);  @Override protected void onPause () / ** * Ring här före onPause, annars kommer en IllegalArgumentException också att kastas. * / stopForegroundDispatch (detta, mNfcAdapter); super.onPause ();  @Override protected void onNewIntent (Intent Intent) / ** * Den här metoden kallas när en ny Intent blir associerad med den aktuella aktivitetsexemplen. * I stället för att skapa en ny aktivitet kommer onNewIntent att ringas. För mer information titta * på dokumentationen. * * I vårt fall kallas den här metoden när användaren bifogar en tagg till enheten. * / hanteraIntent (avsikt);  privat tomt handtagIntent (Intent Intent) // TODO: hantera Intent / ** * @param aktivitet Den motsvarande @linkaktiviteten begär förgrundsförsändelsen. * @paramadapter @link NfcAdapter som används för förgrundsförsändelsen. * / allmän statisk tomgång setupForegroundDispatch (slutaktivitetsaktivitet, NfcAdapter adapter) slutlig Intent intention = new Intent (activity.getApplicationContext (), activity.getClass ()); intent.setFlags (Intent.FLAG_ACTIVITY_SINGLE_TOP); sista PendingIntent pendingIntent = PendingIntent.getActivity (activity.getApplicationContext (), 0, intention, 0); IntentFilter [] filters = new IntentFilter [1]; String [] [] techList = ny sträng [] [] ; // Observera att detta är samma filter som i vårt manifest. filter [0] = nytt IntentFilter (); filter [0] .addAction (NfcAdapter.ACTION_NDEF_DISCOVERED); filter [0] .addCategory (Intent.CATEGORY_DEFAULT); prova filters [0] .addDataType (MIME_TEXT_PLAIN);  fånga (MalformedMimeTypeException e) släng ny RuntimeException ("Kontrollera din mime-typ.");  adapter.enableForegroundDispatch (aktivitet, väntarIntent, filter, techList);  / ** * @param aktivitet Den motsvarande @link BaseActivity begär att stoppa förgrundsförsändelsen. * @paramadapter @link NfcAdapter som används för förgrundsförsändelsen. * / statisk statisk tomgångstoppForegroundDispatch (slutaktivitetsaktivitet, NfcAdapter adapter) adapter.disableForegroundDispatch (aktivitet); 

Nu när du bifogar en tagg och vår app redan är öppen heter OnNewIntent och ingen ny aktivitet skapas.


Läser data från en NDEF-tagg

Det sista steget är att läsa data från taggen. Förklaringarna infogas på lämpliga platser i koden igen. NdefReaderTask är en privat inre klass.

 paketet net.vrallev.android.nfc.demo; importera java.io.UnsupportedEncodingException; importera java.util.Arrays; importera android.app.Activity; importera android.app.PendingIntent; importera android.content.Intent; importera android.content.IntentFilter; importera android.content.IntentFilter.MalformedMimeTypeException; importera android.nfc.NdefMessage; importera android.nfc.NdefRecord; importera android.nfc.NfcAdapter; importera android.nfc.Tag; importera android.nfc.tech.Ndef; importera android.os.AsyncTask; importera android.os.Bundle; importera android.util.Log; importera android.widget.TextView; importera android.widget.Toast; / * * ... andra koddelar * / privat tomt handtagIntent (Intent intention) String action = intent.getAction (); om (NfcAdapter.ACTION_NDEF_DISCOVERED.equals (action)) String type = intent.getType (); om (MIME_TEXT_PLAIN.equals (typ)) Tag tag = intent.getParcelableExtra (NfcAdapter.EXTRA_TAG); NdefReaderTask (). execute (tag);  else Log.d (TAG, "Fel mime typ:" + typ);  annars om (NfcAdapter.ACTION_TECH_DISCOVERED.equals (action)) // Om vi ​​fortfarande skulle använda Tech Discovered Intent Tag tag = intent.getParcelableExtra (NfcAdapter.EXTRA_TAG); String [] techList = tag.getTechList (); String searchedTech = Ndef.class.getName (); för (String tech: techList) if (searchedTech.equals (tech)) ny NdefReaderTask (). execute (tag); ha sönder; 
 / ** * Bakgrundsuppgift för att läsa data. Blockera inte gränssnittets tråd när du läser. * * @author Ralf Wondratschek * * / privatklass NdefReaderTask utökar AsyncTask @Override protected String doInBackground (Tag ... params) Tag tag = params [0]; Ndef ndef = Ndef.get (tag); om (ndef == null) // NDEF stöds inte av denna tagg. returnera null;  NdefMessage ndefMessage = ndef.getCachedNdefMessage (); NdefRecord [] records = ndefMessage.getRecords (); för (NdefRecord ndefRecord: records) om (ndefRecord.getTnf () == NdefRecord.TNF_WELL_KNOWN && Arrays.equals (ndefRecord.getType (), NdefRecord.RTD_TEXT)) försök return readText (ndefRecord);  fånga (UnsupportedEncodingException e) Log.e (TAG, "Unsupported Encoding", e);  returnera null;  Private String readText (NdefRecord-post) kastar UnsupportedEncodingException / * * Se NFC-forumspecifikation för "Text Record Type Definition" vid 3.2.1 * * http://www.nfc-forum.org/specs/ * * bit_7 definierar kodning * bit_6 reserverad för framtida användning, måste vara 0 * bit_5 ... 0 längd av IANA språkkod * / byte [] nyttolast = record.getPayload (); // Hämta Text Encoding String textEncoding = ((nyttolast [0] & 128) == 0)? "UTF-8": "UTF-16"; // Hämta språkkoden int languageCodeLength = nyttolast [0] & 0063; // String languageCode = ny sträng (nyttolast, 1, languageCodeLength, "US-ASCII"); // t.ex. "en" // Hämta texten String (nyttolast, languageCodeLength + 1, nyttolastlängd - languageCodeLength - 1, textEncoding);  @Override protected void onPostExecute (Stringresultat) if (result! = Null) mTextView.setText ("Läs innehåll:" + resultat); 

Appen läser nu innehållet framgångsrikt.



Användbara Apps

För att kontrollera om data läses och skrivs korrekt, gillar jag personligen att använda följande appar:

  • NFC TagInfo av NFC Research Lab för läsning av data
  • TagInfo av NXP SEMICONDUCTORS för läsning av data
  • TagWriter av NXP SEMICONDUCTORS för att skriva data

Slutsats

I denna handledning har jag visat dig hur data från en NDEF-tagg kan extraheras. Du kan utvidga exemplet till andra mime typer och chip teknik; en funktion att skriva data skulle också vara användbar. Det första steget att arbeta med NFC gjordes. Men Android SDK erbjuder mycket fler möjligheter, till exempel en enkel datautbyte (kallad Android Beam).

Om du vill ta din Android-utveckling längre, kolla in det stora utbudet av användbara Android-appmallar på Envato Market. Eller hyr en Android-utvecklare på Envato Studio.


Om författaren

Ralf Wondratschek är en datavetenskapsstudent från Tyskland. Utöver sina studier arbetar Ralf som frilansare inom mobil databehandling. Under de senaste åren har han arbetat med Java, XML, HTML, JSP, JSF, Eclipse, Google App Engine, och naturligtvis Android. Han har publicerat två Android-appar hittills som kan hittas här.

Du kan läsa mer om författarens arbete på hans hemsida vrallev.net.


källor

http://www.nfc-forum.org/home/n-mark.jpg

http://commons.wikimedia.org/wiki/File%3A%C3%9Cberlagert.jpg

http://developer.android.com/images/nfc_tag_dispatch.png