안드로이드 NFC 읽고/쓰기 구현

|

애플 기기는 지원하지 않지만, 안드로이드 기기에선 거의 지원해주는 NFC (Near Field Communication).

RFID와 유사하지만 구현에 따라 양방향이 가능하다.


NFC에서 전송되는 데이터는 NDEF (NFC Data Exchange Format) 이라는 형식을 따른다.

한번에 전송되는 NFC 데이터는 NDEFMessage (android.nfc.NdefMessage) 이고, 하나의 NDEFMessage에는 여러개의 NDEFRecord (android.nfc.NdefRecord) 를 포함한다.


NDEFRecord는 3bit의 TNF(Type Name Field)를 가지며, TNF는 기본적으로 안드로이드의 NdefRecord 클래스에 정의되어 있다.

이 TNF에는 몇가지 제약사항이 있다.

- TNF_EMPTY인 경우 type, id, payload를 가질 수 없다

- TNF_UNKNOWN이나 0x07인 경우 type을 가질 수 없다

- TNF_UNCHANGED는 사용될 수 없다.

이 규칙을 위반한 경우 IllegalArgumentException이 발생하게 된다.


TNF_MEDIA인 경우 type은 mime type이 들어가야 한다.

TNF_UNKNOWN인 경우 데이터(payload)는 mime중 application/octet-stream 과 유사하며, type은 지정하지 않는다.

단순히 notification의 목적이면 TNF_EMPTY를 사용할 수 있다. type, payload가 필요하지 않기 때문.

URL/URI 형식의 데이터를 전송하려면 TNF_ABSOLUTE_URI를 사용하면 된다.


NDEFRecord를 생성하기 위해 createUri(), createMime(), createExternal()같은 몇개의 헬퍼 메소드가 제공되고 있으니 참고.


데이터를 파악하기 위해 TNF, type이 사용되고,

데이터 자체를 위해 id와 payload 필드가 제공된다.


id의 최대 크기는 255바이트,

payload의 최대 크기는 2^32-1 의 크기만큼 담을 수 있다.




1. Permission 추가

AndroidManifest.xml에 NFC permission을 추가한다.




2-1. 쓰기기능 구현

NFC를 통해 데이터를 송신하는 송신측에서는 기본적으로 두개의 인터페이스를 구현해 주어야 한다.


1) android.nfc.NfcAdapter.CreateNdefMessageCallback

이 인터페이스에는 NdefMessage형을 반환하는 createNdefMessage(NfcEvent event) 메소드가 선언되어 있다.

메소드명에서 유추할 수 있듯이, 전송할 데이터를 생성하여 리턴해주어야 한다.


보낼 데이터로 NDEFRecord를 만들고, 이 NDEFRecord로 NDEFMessage를 생성하여 리턴 해 주면 된다.


2) android.nfc.NfcAdapter.OnDefPushCompleteCallback

역시 메소드 이름 그대로 NFC송신이 끝난 상태에서 onNdefPushComplete(NfcEvent event) 메소드가 호출된다.

용도에 따라 사용.



이 두개의 인터페이스를 구현하였다면 기기의 NFC에 등록하는 과정이 필요하다.



mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
mNfcAdapter.setNdefPushMessageCallback(this, this);
mNfcAdapter.setOnNdefPushCompleteCallback(this, this);


NfcAdapter.getDefaultAdapter() 호출시 기기에서 NFC 기능이 불가능하다면 null이 리턴된다.

하드웨어의 NFC 지원 여부는 AndroidManifest.xml에서 uses-feature 로도 선언이 가능하다.


setNdefPushMessageCallback()과 setOnDefPushCompleteCallback()으로 콜백을 등록할 수 있다.

위 코드의 경우에는 액티비티 자체에 콜백을 구현하였으므로 this(액티비티)에 this(콜백)을 지정한 것이라 보면 된다.


이 두개의 메소드는 3개 이상의 인자를 받을 수 있는데, 3번째 인자부터는 등록할 추가 액티비티이다.

하지만 레퍼런스에서는 한번에 하나의 액티비티만 등록할 것을 권장하고 있다.




2-2. 읽기기능 구현

수신부에서의 동작은 세 가지의 Intent로 전달된다.


1) android.nfc.ACTION_NDEF_DISCOVERED ("android.nfc.action.NDEF_DISCOVERED")

NDEF payload 태그가 감지되었을때 발생하는 인텐트. payload가 있는 경우 발생하며, 이 인텐트는 ACTION_TECH_DISCOVERED와 ACTION_TAG_DISCOVERED 인텐트 전에 발생한다.

나머지 두개의 인텐트는 이 인텐트를 처리하는 액티비티의 응답이 끝나고 호출된다.


2) android.nfc.ACTION_TAG_DISCOVERED ("android.nfc.action.TAG_DISCOVERED")

태그가 감지되었을때 발생한다.

하지만 해당 태그에 대해 ACTION_NDEF_DISCOVERED나 ACTION_TECH_DISCOVERED로 응답한 액티비티가 있으면 발생하지 않는다.


3) android.nfc.ACTION_TECH_DISCOVERED ("android.nfc.action.TECH_DISCOVERED")

특정 기능을 위한 태깅시 발생.

즉, activity에 intent-filter를 걸고, 어떤 기능(tech)를 대상으로 하는지 meta-data로 정의를 해 주어야 한다.


자세한 정의 방법은 레퍼런스 참고. ( http://developer.android.com/reference/android/nfc/NfcAdapter.html#ACTION_TECH_DISCOVERED )




각 Intent를 받은 액티비티에서는

android.nfc.NfcAdapter.EXTRA_NDEF_MESSAGES 를 키로 하여

ParcelableArrayExtra를 받아 첫번째 배열에 대해 NdefMessage를 받은 후 데이터를 처리하면 된다.

현재로서는 한번에 하나의 메세지만 전달될 수 있지만 향후 호환성을 위해 배열 형태로 구성되어 있다.(라고 레퍼런스에 명시되어 있다)


API Level 19(4.4, 킷캣-KitKat)부터 NfcAdapter.ReaderCallback 인터페이스도 추가되었다. 

이 콜백은 NfcAdapter.enableReaderMode()와 같이 사용되어진다. 자세한 설명은 생략.


And