Разработка NFC приложений для Android

от автора


NFC (near field communication) – стандартизированная технология обмена данными на короткие расстояния, позволяющая осуществлять взаимодействия между двумя электронными устройствами простым и интуитивно понятным способом. Например, с помощью оснащенного NFC смартфона вы можете делать покупки, раздавать визитные карты, скачивать купоны на скидки и так далее. Множество новых применений для NFC будет найдено в ближайшее время.
Эта статья описывает технологии, использующие NFC и способы их применения на сегодняшний день. Также показано, как использовать NFC в Android приложениях и, наконец, приведены два примера NFC приложений с исходными кодами.

Архитектура технологии NFC

NFC основана на RFID технологии с частотой 13.56 МГц и рабочей дистанцией до 10 см. Скорость обмена данными составляет до 424 кб/сек. По сравнению с другими коммуникационными технологиями, основным преимуществом NFC является быстрота и простота использования. На рисунке ниже видно расположение NFC среди других коммуникационных технологий.

Технология NFC имеет три режима: эмуляция NFC-карты, пиринговый режим и режим чтения/записи.

В режиме эмуляции карты NFC представляет собой аналог чипованной RFID карты со своим модулем безопасности, позволяющим защищать процесс покупки. В пиринговом режиме вы можете делиться информацией, например визитной карточкой, с другими NFC устройствами. В также можете устанавливать WiFi или Bluetooth соединения посредством NFC для передачи больших объемов данных. Режим чтения/записи предназначен для чтения или изменения NFC меток с помощью NFC устройств.
Каждый режим более подробно описан ниже.

Режим эмуляции NFC карты

NFC модуль обычно состоит из двух частей: NFC контроллера и элемента безопасности (ЭБ). NFC контроллер отвечает за коммуникации, ЭБ – за шифрацию и дешифрацию чувствительной к взлому информации.

ЭБ подключается к NFC контроллеру посредством шины SWP (Single Wire Protocol) или DCLB (Digital Contactless Bridge). Стандарты NFC определяют логический интерфейс между хостом и контроллером, позволяя им взаимодействовать через RF-поле. ЭБ реализуется с помощью встроенного приложения или компонента ОС.

Существует три варианта реализации ЭБ: можно встроить его в SIM-карту, SD-карту или в NFC чип.

Операторы связи, такие как CMCC (China Mobile Communication Corporation), Vodafone или AT&T обычно используют решение на SIM-карте, поощряя своих абонентов бесплатной заменой старых SIM-карт на новые, оснащенные NFC.

Пиринговый режим

Два NFC устройства могут легко взаимодействовать друг с другом напрямую, обмениваясь небольшими файлами. Для установления Bluetooth/WiFi соединения необходимо обменяться XML файлом специального формата. В этом режиме ЭБ не используется.

Режим записи/чтения

В данном режиме NFC устройство может читать и записывать NFC метки. Хорошим примером применения является чтение информации с оснащенных NFC «умных» постеров.

Введение в разработку NFC под Android

Android поддерживает NFC с помощью двух пакетов: android.nfc и android.nfc.tech.
Основными классами в android.nfc являются:
NfcManager: Устройства под Android могут быть использованы для управления любыми обнаруженными NFC адаптерами, но поскольку большинство Android устройств поддерживают только один NFC адаптер, NfcManager обычно вызывается с getDefaultAdapter для доступа к конкретному адаптеру.
NfcAdapter работает как NFC агент, подобно сетевому адаптеру на ПК. С его помощью телефон получает доступ к аппаратной части NFC для инициализации NFC соединения.
NDEF: Стандарты NFC определяют общий формат данных, называемый NFC Data Exchange Format (NDEF), способный хранить и передавать различные типы объектов, начиная с MIME и заканчивая ультра-короткими RTD-документами, такими как URL. NdefMessage и NdefRecord – два типа NDEF для определенных NFC форумом форматов данных, которые будут использоваться в коде-примере.
Tag: Когда устройство Android обнаруживает пассивный объект типа ярлыка, карты и т.д., он создает объект типа «метка», помещая его далее в целевой объект и в заключении пересылая в соответствующий процесс.
Пакет android.nfc.tech также содержит множество важных подклассов. Эти подклассы обеспечивают доступ к функциям работы с метками, включающими в себя операции чтения и записи. В зависимости от используемого типа технологий, эти классы разбиты на различные категории, такие как NfcA, NfcB, NfcF, MifareClassic и так далее.
Когда телефон со включенным NFC обнаруживает метку, система доставки автоматически создает пакет целевой информации. Если в телефоне имеется несколько приложений, способных работать с этой целевой информаций, пользователю будет показано окно с предложением выбрать одно из списка. Система доставки меток определяет три типа целевой информации, в порядке убывания приоритета: NDEF_DISCOVERED, TECH_DISCOVERED, TAG_DISCOVERED.
Здесь мы используем целевой фильтр для работы со всеми типами информации начиная с TECH_DISCOVERED до ACTION_TECH_DISCOVERED. Файл nfc_tech_filter.xml используется для всех типов, определенных в метке. Подробности можно найти в документации Android. Рисунок ниже показывает схему действий при обнаружении метки.

Пример 1. Разработка NFC приложения для чтения/записи меток.

Следующий пример показывает функции чтения/записи NFC метки. Для того, чтобы получить доступ к аппаратной части NFC и корректно обрабатывать NFC информацию, объявите эти позиции в файле AndroidManifest.xml.

<uses-permission android:name="android.permission.NFC" /> 

Минимальную версию SDK, которую должно поддерживать ваше приложение — 10, объявите об этом в файле AndroidManifest.xml

<uses-sdk android:minSdkVersion="10"/> In the onCreate function,you can apply the NfcAdapter: public void onCreate(Bundle savedInstanceState) { …… adapter = NfcAdapter.getDefaultAdapter(this); …… }  

Следующий целевой вызов демонстрирует функцию чтения. Если широковещательное сообщение системы равняется NfcAdapter.ACTION_TAG_DISCOVERED, тогда вы можете считать информацию и показать ее.

@Override 	    protected void onNewIntent(Intent intent){ 	        if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())){ 	        mytag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  // get the detected tag 	        Parcelable[] msgs = 	intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); 	            NdefRecord firstRecord = ((NdefMessage)msgs[0]).getRecords()[0]; 	            byte[] payload = firstRecord.getPayload(); 	            int payloadLength = payload.length; 	            int langLength = payload[0]; 	            int textLength = payloadLength - langLength - 1; 	            byte[] text = new byte[textLength]; 	            System.arraycopy(payload, 1+langLength, text, 0, textLength); 	            Toast.makeText(this, this.getString(R.string.ok_detection)+new String(text), Toast.LENGTH_LONG).show(); 	                    } 	    }

Следующий код демонстрирует функцию записи. Перед тем, как определить значение mytag, вы должны убедиться, что метка определена и только потом вписать в нее свои данные.

	If (mytag==Null){ 	    …… 	} 	else{ 	…… 	write(message.getText().toString(),mytag); 	…… 	} 	    private void write(String text, Tag tag) throws IOException, FormatException { 	        NdefRecord[] records = { createRecord(text) }; 	        NdefMessage  message = new NdefMessage(records); 	// Get an instance of Ndef for the tag. 	        Ndef ndef = Ndef.get(tag); // Enable I/O 	        ndef.connect(); // Write the message 	        ndef.writeNdefMessage(message); // Close the connection 	        ndef.close(); 	    }

В зависимости от прочитанной информации вы можете выполнить дополнительные действия, такие как запуск какого-либо задания, переход по ссылке и т.д.

Пример 2. Разработка NFC-приложения, использующего карты MifareClassic

В этом примере для чтения мы будем использовать карты MifareClassic и соответствующий им тип метки. Карты MifareClassic широко используются для различных нужд, таких как идентификация человека, автобусный билет и т.д. В традиционной карте MifareClassic область хранения разбита на 16 зон, в каждой зоне 4 блока, и каждый блок может хранить 16 байт данных.
Последний блок в зоне называется трейлером и используется обычно для хранения локального ключа чтения/записи. Он содержит два ключа, А и В, 6 байт длиной каждый, по умолчанию забитые 00 или FF, в зависимости от значения MifareClassic.KEY_DEFAULT.
Для записи на карту Mifare вы, прежде всего, должны иметь корректное значение ключа (что играет защитную роль), а также успешно пройти аутентификацию.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"   	    package="org.reno"   	    android:versionCode="1"   	    android:versionName="1.0" >    	    <uses-permission android:name="android.permission.NFC" />    	    <uses-sdk android:minSdkVersion="14" />    	    <uses-feature android:name="android.hardware.nfc" android:required="true" />    	    <application   	        android:icon="@drawable/ic_launcher"   	        android:label="@string/app_name" >    	        <activity   	            android:name="org.reno.Beam"   	            android:label="@string/app_name"   	            android:launchMode="singleTop" >    	            <intent-filter>    	                <action android:name="android.intent.action.MAIN" />    	     	                <category android:name="android.intent.category.LAUNCHER" />    	            </intent-filter>    	            <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>   	    </application>    	</manifest>

res/xml/nfc_tech_filter.xml:

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

Пример того, как читать карту MifareClassic:

	private void processIntent(Intent intent) {     	    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);    	    for (String tech : tagFromIntent.getTechList()) {    	        System.out.println(tech);    	    }    	    boolean auth = false;    	    MifareClassic mfc = MifareClassic.get(tagFromIntent);    	    try {    	        String metaInfo = "";    	        //Enable I/O operations to the tag from this TagTechnology object.    	        mfc.connect();    	        int type = mfc.getType();  	        int sectorCount = mfc.getSectorCount();    	        String typeS = "";    	        switch (type) {    	        case MifareClassic.TYPE_CLASSIC:    	            typeS = "TYPE_CLASSIC";    	            break;    	        case MifareClassic.TYPE_PLUS:    	            typeS = "TYPE_PLUS";    	            break;    	        case MifareClassic.TYPE_PRO:    	            typeS = "TYPE_PRO";    	            break;    	        case MifareClassic.TYPE_UNKNOWN:    	            typeS = "TYPE_UNKNOWN";    	            break;    	        }    	        metaInfo += "Card type:" + typeS + "n with" + sectorCount + " Sectorsn, "   	                + mfc.getBlockCount() + " BlocksnStorage Space: " + mfc.getSize() + "Bn";    	        for (int j = 0; j < sectorCount; j++) {    	            //Authenticate a sector with key A.    	            auth = mfc.authenticateSectorWithKeyA(j,    	                    MifareClassic.KEY_DEFAULT);    	            int bCount;    	            int bIndex;    	            if (auth) {    	                metaInfo += "Sector " + j + ": Verified successfullyn";    	                bCount = mfc.getBlockCountInSector(j);    	                bIndex = mfc.sectorToBlock(j);    	                for (int i = 0; i < bCount; i++) {    	                    byte[] data = mfc.readBlock(bIndex);    	                    metaInfo += "Block " + bIndex + " : "   	                            + bytesToHexString(data) + "n";    	                    bIndex++;    	                }    	            } else {    	                metaInfo += "Sector " + j + ": Verified failuren";    	            }    	        }    	        promt.setText(metaInfo);    	    } catch (Exception e) {    	        e.printStackTrace();    	    }    	}

Об авторах

Songyue Wang и Liang Zhang — инженеры в Intel Software and Service Group, разрабатывающие мобильные приложения, в том числе и для Android, и оптимизирующие их под платформу х86.

ссылка на оригинал статьи http://habrahabr.ru/company/intel/blog/194344/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *