company_banner

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

http://software.intel.com/en-us/articles/nfc-application-development-on-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.
Intel
209,00
Компания
Поделиться публикацией

Комментарии 21

    +1
    Спасибо, очень интересная тема!
    Где можно более подробно ознакомиться с «хакерскими» аспектами данной технологии? Насколько низкоуровневым может быть доступ к этому интерфейсу?
    Например, выяснилось, что NFC-модуль Galaxy S4 в связи с патентными ограничениями не читает карточки Mifare Plus (на этой технологии в частности основан питерский Подорожник для проезда в метро). В Galaxy S3 и некоторых других телефонах Подорожник читается, а в S4 — нет (хотя и определяется как NFC-метка, но всеми программами выдается сообщение «эта метка не поддерживается»)
    Можно ли как-то напрямую, в обход API прочитать с него данные?
    Еще интересно — можно ли записывать свою информацию (всякие URL, небольшие текстовые сообщения) на использованные карточки метро?
    Можно ли настроить контроллер в режим прослушивания (т.е. ничего не отвечать, все принимать и скидывать дамп в файл)?

      0
      По документации поддержка чипов MifareClassic и MifareUltralight является опциональной, то есть NFC чип устройства на ОС Андроид может забить на возможность их чтения.

      Можно ли как-то напрямую, в обход API прочитать с него данные?

      Нет. Это аппаратное ограничение.

      Еще интересно — можно ли записывать свою информацию (всякие URL, небольшие текстовые сообщения) на использованные карточки метро?

      Если устройство поддерживает этот тип карт, то можно :).

      Можно ли настроить контроллер в режим прослушивания (т.е. ничего не отвечать, все принимать и скидывать дамп в файл)?

      Да, можно написать приложение, которое будет считывать все теги, которые находятся в зоне действия чипа (Foreground Dispatch System) и записывать их содержимое в файл. Но опять же нужна поддержка этих тегов + экран обязан быть всегда включенным.
        0
        По документации поддержка чипов MifareClassic и MifareUltralight является опциональной, то есть NFC чип устройства на ОС Андроид может забить на возможность их чтения.

        то есть там аппаратные особенности, которые в некоторых чипах могут быть просто не реализованы?

        Нет. Это аппаратное ограничение.

        Совсем аппаратное? Свой драйвер и т.п. не поможет? Бывают ли у таких чипов недокументированные возможности?

        Да, можно написать приложение, которое будет считывать все теги, которые находятся в зоне действия чипа (Foreground Dispatch System) и записывать их содержимое в файл. Но опять же нужна поддержка этих тегов + экран обязан быть всегда включенным.

        Я имел в виду запись дампа обмена между двумя устройствами. Когда-то давно принимал участие в одном проекте, работали с технологией похожей на NFC, так там, когда нужно было выяснить какие-то особенности протокола, а затем проверить свою реализацию — вносили еще одну катушку в поле и записывали обмен на цифровой осциллограф, а затем смотрели:)
          0
          то есть там аппаратные особенности, которые в некоторых чипах могут быть просто не реализованы?

          Да. Там какие-то проблемы с шифрованием данных на метке. Читал на stackoverflow, найти уже не могу :(.

          Нет. Это аппаратное ограничение.

          В таком случае уж лучше купить спец. девайс для чтения таких меток, а не извращаться с драйвером для Андроида :).
      +1
      Хотелось бы узнать, какие модели поддерживают эмуляцию карты, а так же пример реализации.
        0
        Насколько я понимаю (пару месяцев шерстил интернет) проблема не в поддержке со стороны телефонов, а в том, что API для эмуляции не является публичным и для доступа к нему нужен бубен.
          +1
          так вот у меня та же проблема. надеялся, может автор знает или кто-то еще.
            +1
            Тоже интересовал данный вопрос, очень хочется расплачиваться с помощью встроенного в телефон NFC модуля, а не той фигней, которая есть у МТС (к примеру, для заправки авто на лукойле).
              0
              вот нарыл кое-что, сам еще не пробовал сделать. возможно это уже находили.
            0
            Интересно, а эмулировать карту без стороннего ЭБ можно?
          0
          Судя по всему оплата через NFC кроме как в штатах нигде не заработает в ближайшем времени…
            0
            У банка Русский Стандарт в Москве есть. Вот
            Вроде еще ТКС что-то реализует
              +1
              Я наверное неправильно выразился, у нас Приват тоже давно раздает PayPass карты.
              Насколько я знаю, приложение Google Wallet позволяет оплачивать через NFC прямо с телефона без установки всяких сим-карт и прочего добра, добавляешь карту один раз и все.
                +1
                Тут то что делают i-free и ТКС:https://www.tcsbank.ru/about/news/30052013-tcs-ifree/
                Google wallet вполне можно заставить работать в России и где-то еще. В москве достаточно много терминалов с paypass, а все эти приложения используют его протокол. Как заставить работать есть инструкции на xda developers.
                  0
                  Если не затруднит, дайте ссылку. Интересная тема.
                    +1
                    Я нашел этот мануал, про то как заставить работать. А как туда добавить нашу карту — не нашел )
                0
                Вся Азия расплачивается пайпассом и нфц.
                0
                Кто-нибудь знает, может ли NFC эмулировать старые Proximity Cards на 125Khz, хочется открывать дверь в подъезде.
                  0
                  Там же частота другая совсем?
                    0
                    NFC — 13.56 мегагерц, так что врятли.
                    0
                    А можете исходниками поделиться?

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое