검색결과 리스트
학습/용어정리에 해당되는 글 4건
- 2013.07.18 안드로이드 NFC 기본 기능 (NFC Basic)
- 2013.07.04 MVC
- 2013.07.04 RequestJS
- 2013.07.04 JSON
이 문서는 안드로이드에서 기본적인 NFC 작업을 처리하는 방법을 설명하고 있다. 기본적으로 NDEF 메시지 형식의 NFC 데이터를 안드로이드 프레임워크 API를 사용하여 송수신 하는 방법을 설명하며 NDEF 형식이 아닌 다른 형식의 데이터는 어떻게 작업해야 하는 지는 Advanced NFC를 참조하기 바란다.
안드로이드에서 NDEF 데이터를 사용하는 경우는 다음과 같이 2가지 사항이 있을 수 있다.
NFC 태그로 부터 NDEF 데이터를 읽는 것은 검색된 NFC 태그들을 분석하는 태그 디스패치 시스템(tag dispatch system)을 이용해 데이터를 적절하게 분류하고 분류된 데이터를 처리할 수 있는 앱을 실행한다. NFC 태그를 처리하기를 희망하는 앱은 인텐트 필터(intent-filter)를 선언하여 데이터 처리에 대해 요청하면 된다.
안드로이드 빔은 물리적으로 태깅하는 장비들을 이용하여 장비가 NDEF 메시지를 다른 장비에 푸시할 수 있도록 도와준다. 이 것은 블루투스와 같은 다른 무선 기술보다 더 쉽게 데이터를 보낼 수 있는 방법을 제공한다. 왜냐하면 NFC는 블루투스와 달리 장비 검색과 페어링이라는 단계를 요구하지 않기 때문이다.
안드로이드 빔의 연결은 자동으로 2개의 장비가 같은 범위안에 있을 때 연결된다. 안드로이드 빔은 NFC API 집합을 통해 유용하게 사용될 수 있도록 정의되어져 있어 어떠한 앱도 장비간에 정보를 송수신할 수 있도록 설계되어져 있다. 예를 들어 주소록, 브라우저 그리고 유투브 앱은 안드로이드 빔을 통해 주소록 정보, 웹 페이지 그리고 동영상을 다른 장비와 공유할 수 있다.
안드로이드 장비는 NFC가 환경설정 메뉴에서 비활성화되어져 있지 않다면 일반적으로 스크린이 잠금 해제되어져 있을 때 NFC 태그들을 찾을 것이다.
안드로이드 장비가 NFC 태그를 찾았을 때 적절한 동작은 사용하는 앱이 무엇인지 사용자에게 물어보지 않고 대부분 인텐트를 처리할 수 있는 적절한 액티비티가 처리하는 것이다. 왜냐하면 장비들은 매우 가까운 범위에서만 NFC 태그들을 스캔하므로 사용자가 수동적으로 액티비티를 선택하게 만드는 것은 사용자가 태그로 부터 멀어질 때 연결이 끊어져 원하는 작업을 수행하지 못하기 때문이다. 그러므로 당신은 액티비티 선택기가 나타나는 것을 방지되도록 오직 관심있는 태그만을 처리하는 액티비티를 개발해야 한다.
이렇게 개발되도록 돕기 위하여 안드로이드는 스캔된 NFC 태그를 분석하고 파싱하고 파싱된 데이터에 관심있는 앱을 탐색하는 특별한 태그 디스패치 시스템을 제공한다. 이 시스템은 다음과 같은 것을 한다.
NFC 앱을 작성하기에 앞서 태그 디스패치 시스템에서 각기 다른 NFC 태그를 어떻게 파싱하는지와 NDEF 메시지가 감지될 때 태그 디스패치 시스템이 어떻게 수행되는지를 이해하는 것이 중요하다. NFC 태그들은 많은 기술들이 있으며 여러 다른 방법으로 데이터를 태그에 쓸 수 있다. 안드로이드는 NFC 포럼에서 정의하고 있는 NDEF 표준의 대부분을 지원하고 있다.
NDEF 데이터는 하나 혹은 그 이상의 레코드들(NdefRecord)을 포함하고 있는 메시지(NdefMessage) 안에 캡슐화되어져 있다. 각각의 NDEF 레코드는 당신이 생성하고자 한 레코드의 유형에 대한 규약서를 잘 따르는 well-formed 레코드이다.
안드로이드는 또한 NDEF 데이터가 포함되지 않은 다른 태그 형식들도 지원한다. 이러한 기능과 연관된 클래스들을android.nfc.tech 패키지에 정의되어져 있다. 이 기술에 대해 더 알아보고 싶으면 Advanced NFC 토픽을 살펴보기 바란다.
다른 형식의 태그와 작업하는 것은 태그와 통신하기 위해 쓰기 위해 당신만이 사용하는 프로토콜 스택을 만들어야 하는 것이므로 당신이 많은 안드로이드 장비들에서 지원되고 가능한 쉽게 개발하기 위해 NDEF를 사용할 것을 권한다.
참고
NDEF 스펙을 다운받기 위해서는 NFC Forum Specification Download 사이트에서 받을 수 있고 NDEF 레코드들을 어떻게 구성할 수 있는지에 대한 예제는 Creating common types of NDEF records에서 참조할 수 있다.
NFC 태그 배경 지식을 가지고 다음 섹션에서는 어떻게 안드로이드에서 NDEF 형식의 태그들을 핸들링하는 지 자세히 살펴보겠다.
안드로이드 장비가 NDEF 형식의 데이터를 NFC 태그에서 스캔하면 메시지를 파싱하고 데이터의 MIME 타입 혹은 구별을 위한 URI을 찾는 것을 시도한다. 이것이 수행하려면 먼저 시스템은 전체 NDEF 메시지를 해석하는 방법을 결정하기 위해 NdefMessage 안에 있는 NdefRecord를 읽는다.(하나의 NDEF 메시지는 여러개의 NDEF 레코드들을 가질 수 있다.) well-formed NDEF 메시지안에서 첫번째에는 아래의 필드가 포함되어져 있는 NdefRecord가 있다.
3-bit TNF (Type Name Format)
변수 길이 타입 필드를 해석하는 방법을 가리킨다. 유효한 값은 아래 Table 1을 참조하기 바란다.
Variable length type
레코드의 타입을 설명한다. 만약 TNF_WELL_KNOWN을 사용하면 이 필드에 RTD(Record Type Definition)을 명시한다. 유효한 RTD 값들은 Table 2를 참조하기 바란다.
Variable length ID
레코드를 구분하기 위한 ID. 이 필드는 종종 사용되지 않지만 만약 당신이 태그를 구분하는데 필요할지도 모른다.
Variable length payload
당신이 읽거나 쓰기 원하는 실제 데이터 페이로드. 하나의 NDEF 메시지는 여러개의 NDEF 레코드들을 가질 수 있다. 그래서 전체 페이로드가 NDEF 메시지의 첫번째 NDEF 레코드라고 생각하고 처리하지 말아야 한다.
태그 디스패치 시스템은 TNF와 NDEF 메시지에서 MIME 타입 혹은 URI와 매핑을 위한 타입 필드들을 사용한다. 만약 성공적이면 실제 페이로드와 함께 ACTION_NDEF_DISCOVERED 인텐트에 정보를 캡슐화한다. 그러나 태그 디스패치 시스템이 첫번째 NDEF 레코드에 기반한 데이터의 유형을 결정할 수 없을 때가 있는데 이것은 NDEF 데이터가 MIME 타입 혹은 URI와 매핑되어져 있지 않거나 NFC 태그가 그 안에 어떠한 NDEF 데이터도 포함하고 있지 않을 때 발생한다. 이러한 경우 태그의 기술과 페이로드에 대한 정보를 가지고 있는 Tag 객체가 ACTION_NDEF_DISCOVERED 인텐트에 캡슐화된다.
Table 1은 태그 디스패치 시스템이 TNF와 MIME 타입 혹은 URI를 위한 타입 필드들이 매핑되는 방법을 설명하고 있거나 TNF들이 MIME 타입 혹은 URI와 매핑될 수 없다는 것을 설명하고 있다. 후자의 경우 태그 디스패치 시스템은ACTION_TECH_DISCOVERED 로 대체한다.
예를 들어 만약 태그 디스패치 시스템이 TNF_ABSOLUTE_URI 형식의 레코드를 만나면 레코드의 variable length type 필드가 URI에 매핑된다. 태그 디스패치 시스템은 페이로드와 같은 태그에 대한 다른 정보와 함께 ACTION_NDEF_DISCOVERED 인텐트의 데이터 필드안에 URI를 캡슐화 시킨다. 그리고 만약 TNF_UNKNOWN 형식의 레코드라면 TNF_ABSOLUTE_URI 형식의 작업 대신에 태그의 기술들을 캡슐화한 인텐트를 생성한다.
Type Name Format (TNF) | Mapping |
---|---|
TNF_ABSOLUTE_URI | 타입 필드에 따른 URI |
TNF_EMPTY | ACTION_TECH_DISCOVERED 로 대체됨 |
TNF_EXTERNAL_TYPE | 타입 필드에 URN을 기반으로 한 URI. URN은 <domain_name>:<service_name>와 같은 단축형식으로 NDEF 타입 필드에 인코딩된다. 안드로이드는 이것을 vnd.android.nfc://ext/<domain_name>:<service_name> 형식으로 매핑한다. |
TNF_MIME_MEDIA | 타입 필드에 따른 MIME 타입 |
TNF_UNCHANGED | 첫번째 레코드가 유효하지 않음. ACTION_TECH_DISCOVERED로 대체됨 |
TNF_UNKNOWN | ACTION_TECH_DISCOVERED로 대체됨 |
TNF_WELL_KNOWN | Record Type Definition (RTD)에 의존적인 MIME 타입 혹은 URI 로 타입 필드에 설정한다. RTD와 RTD의 매핑에 관한 정보는 Table 2.를 참조 바람. |
Record Type Definition (RTD) | Mapping |
---|---|
RTD_ALTERNATIVE_CARRIER | ACTION_TECH_DISCOVERED로 대체. |
RTD_HANDOVER_CARRIER | ACTION_TECH_DISCOVERED로 대체 |
RTD_HANDOVER_REQUEST | ACTION_TECH_DISCOVERED로 대체 |
RTD_HANDOVER_SELECT | ACTION_TECH_DISCOVERED로 대체 |
RTD_SMART_POSTER | 페이로드 파싱에 따른 URI |
RTD_TEXT | text/plain MIME 타입 |
RTD_URI | URI 페이로드 |
NFC 태그들이 앱에 전달되는 방법
태그 디스패치 시스템은 NFC 태그와 태그를 식별하는 정보를 캡슐화한 인텐트를 생성하고 인텐트에 대한 필터를 등록한 앱에게 인텐트를 전송한다. 만약 하나 이상의 앱에서 인텐트를 받기 원한다면 Activity Chooser가 사용자로 하여금 액티비티를 선택하도록 표시된다. 태그 디스패치 시스템은 3개의 인텐트를 정의할 수 있다. 높은 우선순위부터 낮은 우선순위로 정리하면 다음과 같다.
태그 디스패치 시스템은 기본적으로 다음과 같은 방법으로 동작한다.
가능하다면 언제든지 위 3가지 인텐트 중 가장 구체적인 것이기 때문에 NDEF 메시지들과 ACTION_NDEF_DISCOVERED 인텐트와 함께 동작한다. ACTION_NDEF_DISCOVERED는 사용자에게 최상의 경험을 제공하므로 다른 2가지 인텐트 보다 더 명확하게 앱을 시작시키는 인텐트이다.
장비의 NFC 하드웨어에 접근하고 제대로 NFC 인텐트들을 처리하려면 먼저 AndroidManifest.xml 파일에 다음과 같은 항목을 선언해야 한다.
당신이 핸들링하기 원하는 NFC 태그가 스캔될 때 앱이 시작되기 위해서는 안드로이드 매니페스트에 NFC 인텐트 중 하나, 둘 혹은 세가지 모두에 대한 필터를 등록할 수 있다. 그러나 보통 앱이 시작할 때 대부분을 제어하는데는 ACTION_NDEF_DISCOVERED 인텐트에 대한 필터만 등록하면 된다. ACTION_NDEF_DISCOVERED에 대한 필터를 등록한 앱이 없거나 페이로드가 NDEF가 아닐때는 ACTION_TECH_DISCOVERED 인텐트가 대체된다.
ACTION_TAG_DISCOVERED에 대한 필터링은 너무 일반적인 필터이다. 많은 앱이 ACTION_NDEF_DISCOVERED 혹은 ACTION_TECH_DISCOVERED를 등록하므로 앱은 제일 낮은 우선순위로 시작될 것이다.
ACTION_TAG_DISCOVERED는 오직 ACTION_NDEF_DISCOVERED 혹은 ACTION_TECH_DISCOVERED 에 대한 앱이 존재하지 않을 때 최후의 수단으로 사용하기 위할 때만 유효하다.
항상 그렇지는 않지만 NFC 태그 배포들은 다양하고 매번 다른 2가지 인텐트들로 대체되는 것이 당신의 제어안에 없기 때문에 당신의 태그에는 쓰여진 데이터와 태그의 유형에서 제어하기 위해 NDEF 형식을 사용할 것을 권유한다.
다음 섹션은 인텐트의 각 유형에 따라 필터링 하는 방법을 설명한다.
ACTION_NDEF_DISCOVERED
ACTION_NDEF_DISCOVERED 인텐트를 필터링 하려면 원하는 데이터의 유형과 함께 인텐트 필터를 선언하면 된다. 다음의 예제는 text/plan MIME 타입의 데이터와 함께한 ACTION_NDEF_DISCOVERED 인텐트를 위한 필터 선언이다.
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
다음은 http://developer.android.com/index.html 형식을 갖는 URI에 대한 필터 선언 예제이다.
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"
android:host="developer.android.com"
android:pathPrefix="/index.html"/>
</intent-filter>
ACTION_TECH_DISCOVERED
만약 당신의 앱이 ACTION_TECH_DISCOVERED 인텐트에 대해 필터링 하고 싶다면 XML 자원 파일을 생성해야 하며 파일에는 액티비티가 지원하는 기술들이 tech-list 집합에 명시되어 있어야 한다. 당신의 액티비티가 tech-list 집합이 태그에 의해 지원되는 기술들이 부분 집합에 속하는 것인지를 고려하고 싶다면 Tag 클래스의 getTechList() 메서드를 통해 지원되는 기술의 클래스명들을 획득하면 된다.
예를 들어 스캔된 태그가 MifareClassic, NdefFormatable 그리고 NfcA를 지원한다면 당신의 tech-list 집합은 세가지 모두, 두개 혹은 기술들 중 하나라도 명시해야 당신의 액티비티와 매칭된다.
다음의 샘플은 모든 기술들을 선언한 것이다. 당신은 필요없는 것을 제거하여 사용하기 바란다.
이 파일은 <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>
또한 여러개의 tech-list로 분류할 수 있다. 각각의 tech-list 집합은 독립적으로 고려되고 액티비티가 어떤 tech-list 집합이 getTechList() 메서드에 의해 반환되는 기술들의 부분 집합인지를 매칭 하는데 고려된다. 이것은 기술의 매칭을 위해 AND 와 OR 의미를 제공한다. 아래의 예제는 NfcA와 Ndef 기술을 지원하거나 NfcB와 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>
</resources>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.NfcB</tech>
<tech>android.nfc.tech.Ndef</tech>
</tech-list>
</resources>
AndroidManifest.xml 파일에 <activity> 엘리먼트안에 <meta-data> 엘리먼트를 사용하여 자원 파일을 명시한다.
<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>
태그 기술들과 작업하는 것과 ACTION_TECH_DISCOVERED 인텐트에 대한 자세한 것은 Advanced NFC 문서의 지원되는 태그 기술들과 작업하기(Working with Supported Tag Technologies) 를 참조하기 바란다.
ACTION_TAG_DISCOVERED
ACTION_TAG_DISCOVERED 에 대한 필터 선언은 다음과 같이 하면 된다.
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>
인텐트로 부터 정보 획득
액티비티가 NFC 인텐트에 의해 시작되면 인텐트로 부터 스캔된 NFC 태그에 대한 정보를 획득할 수 있다. 인텐트에는 다음과 같은 스캔된 태그에 대한 extra들이 포함되어져 있다.
extra들을 얻기 위해서는 액티비티가 스캔된 태그를 확신시킬 수 있는 NFC 인텐트들 중 하나와 함께 런칭되었는지 체크한 후 인텐트에서 획득한다. 아래의 예제는 ACTION_NDEF_DISCOVERED 인텐트인지 확인 후 인텐트에서 NDEF 메시지를 얻는다.
선택적으로 당신은 인텐트로 부터 Tag 객체를 얻을 수 있다. 이 객체에는 페이로드가 포함되어 있으며 태그의 기술들을 열람할 수 있다.
이 섹션에서는 NFC 태그에 쓰거나 안드로이드 빔을 통해 전송하 때 사용하는 NDEF 레코드들의 일반적 타입들을 생성하는 방법과 레코드와 연관된 인텐트 필터를 생성하는 방법도 설명한다. 다음의 모든 예제는 태그 혹은 빔을 통해 NDEF 메시지의 첫번째 NDEF 레코드에 작성하는 예이다.
TNF_ABSOLUTE_URI
TNF_ABSOLUTE_URI 레코드는 다음과 같이 생성하여 NdefMessage 의 첫번 째 레코드에 저장한다.
인텐트 필터는 다음과 같다.
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"
android:host="developer.android.com"
android:pathPrefix="/index.html"/>
</intent-filter>
TNF_MIME_MEDIA
TNF_MIME_MEDIA NDEF 레코드는 다음과 같이 생성하여 NdefMessage 의 첫번 째 레코드에 저장한다.
인텐트 필터는 다음과 같다.
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/com.example.android.beam"/>
</intent-filter>
RTD_TEXT를 포함한 TNF_WELL_KNOWN
다음과 같이 TNF_WELL_KNOWN NDEF 레코드를 생성한 후 NdefMessage 의 첫번 째 레코드에 저장한다.
인텐트 필터는 다음과 같다.
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
RTD_URI를 포함한 TNF_WELL_KNOWN
다음과 같이 TNF_WELL_KNOWN NDEF 레코드를 생성한 후 NdefMessage 의 첫번 째 레코드에 저장한다.
인텐트 필터는 다음과 같다.
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"
android:host="example.com"
android:pathPrefix=""/>
</intent-filter>
TNF_EXTERNAL_TYPE
다음과 같이 TNF_EXTERNAL_TYPE NDEF 레코드를 생성한 후 NdefMessage 의 첫번 째 레코드에 저장한다.
인텐트 필터는 다음과 같다.
<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="/example.com:externalType"/>
</intent-filter>
안드로이드 장비와 안드로이드 기반이 아닌 장비간에 향상된 방법을 지원하는 위해 보다 일반적인 NFC 태그에 배포가 가능한 TNF_EXTERNAL_TYPE을 사용한다.
참고
TNF_EXTERNAL_TYPE에 대한 URNs는 urn:nfc:ext:example.com:externalType의 표준형식을 가진다. 그러나 NFC 포럼의 RTD 규약서에는 URN의 urn:nfc:ext: 부분은 NDEF 레코드로 부터 생략한다. 그래서 당신은 도메인(example.com)과 유형(externalType)을 콜론(':')으로 구분하여 제공해야 한다. TNF_EXTERNAL_TYPE이 디스패치될 때 안드로이드는urn:nfc:ext:example.com:externalType URN을 인텐트 필터에 선언한 것에 따라vnd.android.nfc://ext/example.com:externalType URI로 변경한다.
Android Application Records (AAR)
안드로이드 4.0 (API level 14)에서 소개되는 Android Application Record (AAR)은 NFC 태그가 스캔될 때 시작되는 앱에게 강력한 확실성을 제공한다. AAR은 NDEF 레코드에 포함된 앱의 패키지 이름을 가진다. NDEF 메시지의 어떠한 NDEF 레코드에도 AAR를 추가할 수 있다. 왜냐하면 안드로이드는 NDEF 메시지 전체에서 AAR들을 찾기 때문이다. 만약 AAR이 발견되면 AAR에 있는 패키지 명에 근거하여 앱을 시작한다. 만약 장비에 해당하는 앱이 없다면 앱을 다운로드 받기 위해 안드로이드 마켓이 런칭된다.
AAR은 만약 당신이 같은 인텐트에 대한 필터링을 가진 다른 앱으로 부터 보호하고 잠재적으로 당신이 배치한 특정 태그를 처리하는데 유용하다. AAR은 패키지 이름이 반드시 사용되므로 인텐트 필터링 같은 액티비티 레벨이 아닌 오직 애플리케이션 레벨에서만 지원된다. 만약 액티비티 레멜에서 인텐트를 처리하기를 원한다면 AAR이 아닌 intent-filter 를 사용하기 바란다.
만약 태그가 AAR을 포함하고 있다면 태그 디스패치 시스템은 다음과 같은 방법으로 태그 정보를 전달한다.
참고
당신은 AARs와 포그라운드 디스패치 시스템(foreground dispatch system)과 함께하는 인텐트 디스패치 시스템(intent dispatch system)을 재정의(override)할 수 있다. 포그라운드 디스패치 시스템은 현재 보여지고 있는(foreground) 액티비티가 NFC 태그가 발견되었을 때 우선적으로 가질 수 있게 한다. 이 방법을 통해 액티비티는 AARs과 인텐트 디스패치 시스템을 재정의하기 위해 포그라운드로 있어야 한다.
만약 당신은 AAR을 포함하지 않은 스캔되는 태그를 필터링하기 원한다면 일반적으로 인텐트 필터(intent-filter)를 선언할 수 있다. 이 것은 AAR을 포함하지 않은 다른 태그들에 관심있는 앱이라면 유용한 방법이다. 예를 들어 어쩌면 당신은 앱이 당신의 독점적인 태그뿐만 아니라 타사에 의해 배포된 일반적인 태그에 대한 처리도 보증하기 원한다면 AARs가 안드로이드 4.0 이상의 장비에서만 지원된다는 것을 유의하여 태그를 배포할 때 광범위한 장비들을 지원하기 위해 AARs와 MIME 타입/URI의 조합을 사용하기 바란다. 추가적으로 당신이 NFC 태그를 배포할 때 대부분의 장비(안드로이드 장비 뿐만 아니라 다른 장비들)에 대한 지원을 활성화하기 위해 당신의 NFC 태그를 작성하는 방법을 생각하기 바란다. 당신은 앱을 구별하기 쉽게하기 위해 상대적으로 고유한 MIME 타입 혹은 URI를 정의할 수 있다.
안드로이드는 AAR을 생성하기 위해 createApplicationRecord() 와 같은 간단한 API를 제공한다. 당신은 오직 NdefMessage안 어디든지 AAR을 포함하면 된는데 AAR이 NdefMessage의 유일한 레코드가 아니라면 NdefMessage의 첫번째 레코드로 사용하지 않아야 한다. 이것은 안드로이드 시스템이 앱이 필터링하는 인텐트를 생성하는데 사용하는 MIME 타입 혹은 태그의 URI를 결정하기 위해 NdefMessage 의 첫번째 레코드를 확인하기 때문이다. 다음은 AAR을 생성하는 예제이다.
안드로이드 빔은 2개의 안드로이드 장비간에 P2P 데이터 교환이 가능하게 한다. 빔을 통해 데이터를 다른 장비에 전송하기 원하는 앱은 포그라운드로 동작하고 있어야 하고 데이터를 받는 장비는 연결 해제 되어져 있어야 한다. 수신 장비와 충분히 근접하게 접촉되면 빔을 쏘는 장비에는 "Touch to Beam" 이라는 사용자 인터페이스가 표시되어 사용자가 수신 장비에 메시지를 전송할지 말지를 선택할 수 있다.
참고
포그라운드 NDEF 푸싱은 API level 10에서도 가능하며 안드룅드 빔과 유사한 기능을 제공한다. 하지만 deprecated 상태이다. 더 자세한 것은 enableForgroundNdefPush() 를 살펴 보기 바란다.
앱에서 안드로이드 빔을 활성화하기 위해서는 2개의 메서드 중 하나를 호출하면 된다.
액티비티는 오직 한번에 NDEF 메시지를 보낼 수 있다. 그래서 양쪽다 사용할 경우 setNdefPushMessageCallback()이 setNdefPushMessage() 보다 우선순위가 높다 먼저 설정된다.
안드로이드 빔을 사용하기 위해서는 다음과 같은 가이드라인을 따라주면 된다.
참고
만약 액티비티가 안드로이드 빔이 활성화 되어 있고 포그라운드로 동작하고 있다면 표준 인텐트 디스패치 시스템은 비활성화되어 있어 인텐트 필터에 해당하는 태그가 스캔되어도 전달 받지 못한다. 그러나 만약 포그라운드 디스패치(foreground dispatching)가 활성화 되어있다면 설정된 인텐트 필터에 의한 태그를 스캔할 수 있다. (포그라운드 디스패치는 Advanced NFC 참조)
안드로이드 빔을 활성화 하려면
일반적으로, 2개의 장비들이 통신할 수 있는 영역에 있을 때 액티비티가 한번에 같은 NDEF 메시지를 푸시하는데는 setNdefPushMessage()를 사용하고 앱이 현재의 상황정보(context)에 따르고 사용자의 앱 안에서 기능의 사용에 따라 NDEF 메시지를 푸시하기 원하면 setNdefPushMessageCallback()을 사용한다.
다음의 예제는 앱티비티의 onCreate() 메서드에서 NfcAdapter.CreateNdefMessageCallback을 호출하는 것이다.
참고로 위의 예제에서 AAR에 관한 코드를 주석처리 했다. 만약 필요하지 않다면 지워도 상관없다. AAR의 주석을 제거하여 코드가 실행되게 한다면 해당 패키지 명으로 된 AAR이 안드로이드 빔 메시지를 항상 수신하도록 명시하는 것이고 만약 장비에 해당 앱이 없으면 안드로이드 마켓에서 다운로드 받도록 이동한다. 그러므로 아래의 인텐트 필터 선언은 AAR을 지원하는 안드로이드 4.0 이후의 장비에서는 선언할 필요가 없다.
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/com.example.android.beam"/>
</intent-filter>
위와 같이 인텐트 필터를 선언하면 com.example.android.beam 앱은 현재 NFC 태그를 스캔했거나 com.example.android.beam 형식의 AAR에 대한 안드로이드 빔을 수신했거나 NDEF 형식의 메시지가 android/com.example.android.beam 형식의 MIME 레코드가 포함되어져 있을 때 시작될 것이다.
AAR이 앱이 실행되거나 다운로드를 보장한다고 해도 AAR에 의해 명시된 패키지의 메인 액티비티가 항상 실행되는 대신 앱안에서 사용자의 선택에 의한 액티비티가 실행되기를 원한다면 AAR은 액티비티 레벨로 세분하여 실행시킬 수 없으므로 인텐트 필터를 선언 방식을 사용할 것을 권고한다. 그리고 아직까지 많은 안드로이드 장비들이 AAR을 지원하지 않으므로 인텐트 필터 선언 방식으로 하는 것이 당분간은 더 유효할 것이다. 그리고 만약을 대비해서 필터를 선언하는 것뿐만 아니라 NDEF 메시지들의 첫 번째 레코드에 식별 정보를 포함하기 바란다.(식별 번호를 포함하는 것은 "NDEF 레코드의 일반적 타입들 생성하기"를 참조 바람)
MVC는 서버 사이트 코드를 구조화하고 모듈로 만들며 유지보수가 용의하도록 돕는 매우 잘 알려진 디자인 패턴입니다. 그러면 프런트 앤드에서 MVC를 사용하려면 어떻게 해야 할까요? 자바스크립트에서 이 디자인패턴을 적용할 수 있을 까요? 만약 여러분이 자바스크립트를 단지 애니메이션과 폼 유효성 검사, 100라인이 넘지 않는 간단한 처리를 위해서 사용한다면 MVC를 사용해서 여러분의 스크립트 파일을 구조화할 필요 없습니다. RequireJS도 사용할 필요 없을 겁니다. 하지만, 뷰(view)가 많은 리치 웹 앱을 제작 중이라면 반드시 필요합니다!
Model
모델은 도메인 개체 그 자체이다. 도메인은 프로그램 내에서 동일한 의미를 갖는 대상이다. 보통 Data 그 자체와 동일시 되지만, 이 외의 데이터를 조작할 수 있는 기능이 추가되기도 한다. 구현과 상황에 따라서는 단순히 데이터소스에 접근하는 DAO 역할을 하거나, 파일 시스템 자체가 되거나, 라이브러리 세트가 된다.
디스플레이.
사용자(Client. 사람이 아닌 기계 혹은 동물일수도 있다. 어플리케이션이 이용되는 타겟이라고 생각하자) 에게 제공되는 UI Layer를 말한다. 더욱 큰 의미를 포함하면 눈으로 이미지가 곁들여지거나 글자로 이루어지지 않은 바이트 코드의 나열이나 음악 파일등이라도, Client 가 이해할 수 있다면 View가 될 수 있다.
보통 Web Application 등에서는 View는 HTML/CSS 로 렌더링된 화면을 가르킨다.
MVC를 비롯한 여러 프레임워크들이 나온 이유는 명확하다.
각 계층의 분리로 재활용성을 높이고 중복을 막자는 것이다. 각 계층의 강한 결합이 발생한다면 애초에 프레임워크를 적용하는 의미가 없다.
이 둘의 의존성을 어떻게 제어하느냐에 따라 MVC, MVP, MVVM … etc 등으로 나뉘게 된다.
이들은 모델과 뷰의 통신을 담당한다. 이들의 차이점을 한번 훓어보자.
모든 입력은 Controller에서 처리된다. 특정 입력이 들어오면 Controller는 그 입력에 해당하는 Model을 선택하여 처리하게 한다.
Controller는 입력에 따라 Model을 업데이트하고, 결과에 따라 다른 View를 선택한다. Controller는 View를 선택할 수 있기에 View를 여러개 관리할 수 있다.
일반적으로 View는 Model을 사용하여 업데이트를 하지만, Model을 관리하는 것은 Controller이므로 사실상 View는 Model을 직접적으로 생성하거나 관리하는 것은 아니다. Model을 이용하거나 이용될 뿐이다.
Controller는 Model을 조작하고 View를 선택하지만 View를 직접 업데이트하진 않는다.
이 경우에는 View와 Model의 관계가 어느정도 있으며
어느것이 되었든 View와 Model의 어느정도의 의존성은 피할 수 없다. 이것이 Controller를 사용하는 MVC의 문제점이라면 문제점이다.
MVC 패턴의 좋은 구성은 최대한 이 둘의 의존성을 낮추는게 관건이다.
조금 억지스러운 예를 들어보자.
View와 Model이 클럽에 온 소극적인 남녀라면 Controller는 이 둘을 부킹해주는 실력좋은 웨이터이다. 여기서 소극적인 이라는게 중요하다. 물론 웨이터는 수 많은 요청에 의해 오늘도 매번 부킹에 성공할 것이다.
View와 Model 사이의 상호작용을 담당한다. 또한, 이 경우 사용자의 입력 처리는 Controller 가 아닌 View가 담당한다. View가 이벤트를 Presenter에 전달하면 이벤트에 맞춰 Presenter는 Model을 조작하고 그 결과를 다시 View에 바인딩하여 View의 요소들이 업데이트된다.
Controller는 단순히 View를 선택하고 Model을 조작한 뒤 실제 회면 갱신은 View와 Model의 상호작용으로 이루어지지만 Presenter 를 사용한 MVP에서는 Presenter가 Model을 조작하고 관리하며 변경이 있으면 Model에 따라 View를 업데이트하게 된다.
실제 구현체로 생각해본다면 Presenter는 Model과 View의 인스턴스를 모두 가지고 있어야 할 것이다. View가 섬이고 Model이 육지라면 그 사이를 이어주는 다리와 같다고 보면 될 듯 싶다.
View와 Presenter는 1:1 관계로 맺어지며 Presenter는 보통 Model보다는 View에 더 닮은 구조로 디자인된다.
MVC와는 다르게 View와 Model의 관계가 전혀 없으며 단지 View는 Presenter라는 것을 하나씩 가지고 있게 된다. 그리고 입력 처리를 View에서 처리한다는 점도 큰 차이점이 된다.
이 녀석을 사용하면 View와 Model의 의존관계가 완전히 없어진다.
View의 표현을 담당한다고 보면 되겠다.
MVP와 매우 비슷하지만 큰 차이점이라면 비중이 View에 좀더 치우쳐 있다는 점이며, Presenter는 View에 상당한 의존성이 있었지만, Controller, Presenter의 위치인 ViewModel은 View와 아무런 관련이 없다. 여러 View들은 하나의 ViewModel을 선택하여 바인딩하고 업데이트를 받는다.
ViewModel의 디자인은 View보다는Model에 비슷하게 구성된다. 보통 ViewModel이 변경되면 자동으로 View에 업데이트되는 방식으로 구현된다.
Model이 순수한 Model이라면 ViewModel은 View를 위한 모든 커스터마이징을 제공하는 Model이다.
좀 억지를 부려보면, ViewModel이 회사라면 View는 근무하는 사원에 가깝다. 회사는 사원의 여러 근무에 대한 환경을 제공한다. 이윤을 위해서라면 회사는 그 무엇과도 거래하고 연결한다.
min
안드로이드 NFC 기본 기능 (NFC Basic) (0) | 2013.07.18 |
---|---|
RequestJS (0) | 2013.07.04 |
JSON (0) | 2013.07.04 |
RequireJS는 AMD(Asynchronous Module Definition)의 구현체입니다. AMD란 모듈을 정의하는 방법과 모듈이 필요할 때 비동기로 로딩하는 방법을 정의한 API 입니다. 제임스 버크(James Burke)씨가 개발했는데, 2년간 개발해서 겨우 버전 1.0을 찍었습니다. 여러분은 RequireJS로 Javascript코드를 모듈화 할 수 있고 비동기로 관리하면서 여러파일을 병렬로 다운로드 할 수 있습니다. 스크립트 파일이 필요할 때만 병렬로 로딩되기 때문에, 페이지 로딩 속도는 빨라집니다.
min
안드로이드 NFC 기본 기능 (NFC Basic) (0) | 2013.07.18 |
---|---|
MVC (0) | 2013.07.04 |
JSON (0) | 2013.07.04 |
1. JSON 이란?
JSON 에 대한 설명은 공식 홈페이지나 위키에 가서 확인하는게 빠를거 같습니다.
JSON 공식 홈페이지 : http://www.json.org
아래 개요 사이트에 가면 친절하게 한국어로 적혀있습니다.
JSON 개요 : http://www.json.org/json-ko.html
JSON (JavaScript Object Notation)은 경량의 DATA-교환 형식이다. 이 형식은 사람이 읽고
쓰기에 용이하며, 기계가 분석하고 생성함에도 용이하다. JavaScript Programming
Language, Standard ECMA-262 3rd Edition - December 1999의 일부에 토대를 두고 있다.
JSON은 완벽하게 언어로 부터 독립적이지만 C-family 언어 - C, C++, C#, Java, JavaScript,
Perl, Python 그외 다수 - 의 프로그래머들에게 친숙한 관습을 사용하는 텍스트 형식이다. 이
러한 속성들이 JSON을 이상적인 DATA-교환 언어로 만들고 있다.
간추려서 말하면, JSON을 지원하는 여러 다양한 언어(C, C++, C#, Java, PHP, Javascript 등...)에서 자료를 쉽게 주고 받을 수 있다고 볼 수 있습니다.
2. Java - JSON
JSON 은 바로 사용하지 못하고 언어에 맞게 별도의 컴파일 과정을 거친 후, 사용할 수 있습니다.
C 의 경우 컴파일 후에 필요한 파일들 복사하고 헤더 파일을 등록 후에 사용하는 것 처럼, Java 에서도 제공된 라이브러리를 통해서 간단하게 사용할 수 있습니다.
3. json-simple 로 json 사용하기
사전에 TCP, UDP 통신등으로 데이터를 주고 받을 수 있도록 구현이 된 상태에서 진행하도록 합니다.
먼저 데이터를 넣는 방법입니다.
아래와 같이 JSONObject를 선언한 다음에 put을 통해서 데이터를 집어 넣어 줍니다.
JSONObject obj;
obj = new JSONObject();
obj.put("key1", "value1");
obj.put("key2", "value2");
위와 같이 만들어진 obj를 통신을 사용해서 보내고자 하는 곳으로 넘겨주면 됩니다.
받게 되는 곳에서는 위의 obj를 받게 됩니다.
이 때, 받은 자료를 value 라는 String 에 저장을 했습니다.
받은 데이터를 JSON 문법으로 해석합니다.
그 다음 get을 통해서 키를 입력하면 값을 받을 수 있습니다.
JSONObject jsonObj;
jsonObj = (JSONObject) JSONValue.parse(value);
String tmp;
tmp = (String) jsonObj.get("key2");
system.out.println(tmp);
위와 같이 했을 때, tmp 는 value2 라는 값을 가지게 됩니다.
JSON.parse(text [, reviver])
이 함수로 JavaScript 구문 분석 오류("SCRIPT1014: 잘못된 문자입니다.")가 발생되면 입력 테스트는 JSON 구문을 따르지 않습니다. 오류를 수정하려면 다음 중 하나를 수행합니다.
text 인수를 수정하여 JSON 구문을 따르도록 합니다. 자세한 내용은 JSON 개체의 BNF 구문 주석을 참조하세요.
텍스트 인수가 JSON.stringify와 같은 JSON 준수 구현으로 serialize되는지 확인합니다.
다음 예제에서는 JSON.parse를 사용하여 JSON 문자열을 개체로 변환합니다.
var jsontext = '{"firstname":"Jesper","surname":"Aaberg","phone":["555-0100","555-0120"]}'; var contact = JSON.parse(jsontext); document.write(contact.surname + ", " + contact.firstname); // Output: Aaberg, Jesper
다음 예제에서는 JSON.stringify를 사용하여 배열을 JSON 문자열로 변환한 다음 JSON.parse를 사용하여 문자열을 배열로 변환하는 방법을 보여 줍니다.
var arr = ["a", "b", "c"]; var str = JSON.stringify(arr); document.write(str); document.write ("<br/>"); var newArr = JSON.parse(str); while (newArr.length > 0) { document.write(newArr.pop() + "<br/>"); } // Output: var arr = ["a", "b", "c"]; var str = JSON.stringify(arr); document.write(str); document.write ("<br/>"); var newArr = JSON.parse(str); while (newArr.length > 0) { document.write(newArr.pop + "<br/>"); } // Output: ["a","b","c"] c b a
reviver 함수는 ISO(International Organization for Standardization) 날짜 문자열의 JSON 표현을 UTC(협정 세계 표준시) 형식 Date 개체로 변환하는데 흔히 사용됩니다.
이 예제에서는 JSON.parse를 사용하여 ISO 형식 날짜 문자열을 deserialize합니다. dateReviver 함수는 ISO 날짜 문자열처럼 형식이 지정된 멤버의 Date 개체를 반환합니다.
var jsontext = '{ "hiredate": "2008-01-01T12:00:00Z", "birthdate": "2008-12-25T12:00:00Z" }'; var dates = JSON.parse(jsontext, dateReviver); document.write(dates.birthdate.toUTCString()); function dateReviver(key, value) { var a; if (typeof value === 'string') { a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); if (a) { return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6])); } } return value; }; // Output: // Thu, 25 Dec 2008 12:00:00 UTC
요구 사항
지원되는 문서 모드: Internet Explorer 8 표준, Internet Explorer 9 표준, Internet Explorer 10 표준. Windows 스토어 응용 프로그램에서도 지원됩니다. 버전 정보를 참조하십시오.
지원되지 않는 문서 모드: Quirks, Internet Explorer 6 표준, Internet Explorer 7 표준
min
안드로이드 NFC 기본 기능 (NFC Basic) (0) | 2013.07.18 |
---|---|
MVC (0) | 2013.07.04 |
RequestJS (0) | 2013.07.04 |
RECENT COMMENT