NFC 기초

이 문서에서는 Android에서 개발자가 실행하는 기본 NFC 작업을 설명합니다. NFC 데이터를 NDEF 메시지 형식으로 주고받는 방법과 이러한 기능을 지원하는 Android 프레임워크 API에 관해 설명합니다. 비 NDEF 데이터를 사용한 작업을 비롯한 고급 주제는 고급 NFC를 참조하세요.

NDEF 데이터 및 Android로 작업할 때 두 가지 주요 사용 사례가 있습니다.

  • NFC 태그에서 NDEF 데이터 읽기
  • Android Beam™을 사용하여 한 기기에서 다른 기기로 NDEF 메시지 공유

NFC 태그에서 NDEF 데이터를 읽는 작업은 태그 디스패치 시스템에서 처리됩니다. 이 시스템은 검색된 NFC 태그를 분석하고 데이터를 적절하게 분류하며 분류된 데이터에 관심이 있는 애플리케이션을 시작합니다. 검사된 NFC 태그를 처리하려는 애플리케이션은 인텐트 필터를 선언하고 데이터 처리를 요청할 수 있습니다.

Android Beam™ 기능을 사용하면 기기를 물리적으로 함께 탭하여 NDEF 메시지를 한 기기에서 다른 기기로 푸시할 수 있습니다. NFC에서는 수동 기기 검색이나 페어링이 필요하지 않기 때문에 이 상호작용 방식을 사용하면 블루투스와 같은 다른 무선 기술보다 데이터를 더 쉽게 전송할 수 있습니다. 두 기기가 일정한 범위 내에 있으면 자동으로 연결이 시작됩니다. Android Beam은 일련의 NFC API를 통해 사용할 수 있으므로 모든 애플리케이션이 기기 간에 정보를 전송할 수 있습니다. 예를 들어 연락처, 브라우저 및 YouTube 애플리케이션은 Android Beam을 사용하여 연락처, 웹페이지, 동영상을 다른 기기와 공유합니다.

태그 디스패치 시스템

기기의 설정 메뉴에서 NFC가 중지되어 있지 않으면 화면 잠금이 해제될 때 일반적으로 Android 구동 기기에서 NFC 태그를 찾습니다. Android 구동 기기에서 NFC 태그를 발견할 경우 사용자에게 어떤 애플리케이션을 사용할지 묻지 않은 채 가장 적절한 활동이 인텐트를 처리하도록 하는 것이 좋습니다. 기기는 매우 근접한 범위에서 NFC 태그를 검사하므로 사용자가 직접 활동을 선택하도록 할 경우 기기를 태그에서 멀리 이동하게 하여 연결이 끊길 수 있습니다. 활동이 관심을 갖는 NFC 태그만 처리하도록 활동을 개발해야 활동 선택기가 표시되지 않습니다.

이를 위해 Android는 검사된 NFC 태그를 분석하고 파싱한 후 검사된 데이터에 관심이 있는 애플리케이션을 찾는 특수 태그 디스패치 시스템을 제공합니다. 작업 단계는 다음과 같습니다.

  1. NFC 태그를 파싱한 다음 MIME 유형 또는 태그에서 데이터 페이로드를 식별하는 URI를 확인합니다.
  2. MIME 유형 또는 URI와 페이로드를 인텐트에 캡슐화합니다. 이 두 가지 단계는 NFC 태그가 MIME 유형 및 URI에 매핑되는 방법에서 설명합니다.
  3. 인텐트에 기반하여 활동을 시작합니다. 이 단계는 NFC 태그가 애플리케이션에 디스패치되는 방법에서 설명합니다.

NFC 태그가 MIME 유형 및 URI에 매핑되는 방법

NFC 애플리케이션을 작성하기 전에 여러 유형의 NFC 태그, 태그 디스패치 시스템이 NFC 태그를 파싱하는 방법, 태그 디스패치 시스템이 NDEF 메시지를 감지할 때 하는 특별한 작업을 이해하는 것이 중요합니다. NFC 태그는 다양한 기술로 제공되며 NFC 태그에는 다양한 방식으로 데이터가 기록될 수 있습니다. Android는 NFC 포럼에서 정의하는 NDEF 표준을 가장 잘 지원합니다.

NDEF 데이터는 하나 이상의 레코드(NdefRecord)를 포함하는 메시지(NdefMessage) 내에서 캡슐화됩니다. 각 NDEF 레코드는 만들려는 레코드 유형의 사양에 따라 올바른 형식을 갖춰야 합니다. Android는 NDEF 데이터를 포함하지 않는 다른 유형의 태그도 지원하며 개발자는 android.nfc.tech 패키지의 클래스를 사용하여 이러한 태그로 작업할 수 있습니다. 이러한 기술에 관해 자세히 알아보려면 고급 NFC 주제를 참조하세요. 이러한 다른 유형의 태그를 사용하려면 자체 프로토콜 스택을 작성하여 태그와 통신해야 하므로 개발 용이성과 Android 구동 기기 지원을 최대화 하기 위해 가능하면 NDEF를 사용하는 것이 좋습니다.

참고: NDEF 사양 전체를 다운로드하려면 NFC 포럼 사양 및 애플리케이션 문서 사이트로 이동하세요. NDEF 레코드를 구성하는 방법의 예는 일반적인 유형의 NDEF 레코드 만들기를 참조하세요.

지금까지 NFC 태그에 관한 배경 지식을 소개했으므로 다음 섹션에서는 Android에서 NDEF 형식의 태그를 처리하는 방법을 자세히 설명합니다. Android 구동 기기는 NDEF 형식의 데이터가 포함된 NFC 태그를 검사할 때 메시지를 파싱하고 데이터의 MIME 유형 또는 식별 URI를 파악하려고 합니다. 이를 위해 시스템은 NdefMessage 내에서 첫 번째 NdefRecord를 읽고 전체 NDEF 메시지를 해석하는 방법을 결정합니다(하나의 NDEF 메시지가 여러 NDEF 레코드를 가질 수 있음). 올바른 형식의 NDEF 메시지에는 첫 번째 NdefRecord에 다음과 같은 필드가 포함되어 있습니다.

3비트 TNF(Type Name Format)
가변 길이 유형 필드를 해석하는 방법을 나타냅니다. 유효한 값은 표 1에 설명되어 있습니다.
가변 길이 유형
레코드 유형을 설명합니다. TNF_WELL_KNOWN을 사용하는 경우 이 필드를 사용하여 RTD(Record Type Definition)를 지정합니다. 유효한 RTD 값은 표 2에 설명되어 있습니다.
가변 길이 ID
레코드의 고유 식별자입니다. 이 필드는 자주 사용되지 않지만 태그를 고유하게 식별해야 하는 경우 ID를 만들 수 있습니다.
가변 길이 페이로드
읽거나 쓰고자 하는 실제 데이터 페이로드입니다. 하나의 NDEF 메시지에 여러 NDEF 레코드가 포함될 수 있으므로 전체 페이로드가 NDEF 메시지의 첫 번째 NDEF 레코드에 있다고 가정해서는 안 됩니다.

태그 디스패치 시스템은 TNF 및 유형 필드를 사용하여 MIME 유형 또는 URI를 NDEF 메시지에 매핑하려고 합니다. 매핑에 성공하면 실제 페이로드와 함께 ACTION_NDEF_DISCOVERED 인텐트 내에 이 정보를 캡슐화합니다. 그러나 태그 디스패치 시스템이 첫 번째 NDEF 레코드에 기반하여 데이터 유형을 확인할 수 없는 경우가 있습니다. 이는 NDEF 데이터를 MIME 유형 또는 URI에 매핑할 수 없거나 NFC 태그에 시작할 NDEF 데이터가 포함되지 않은 경우에 발생합니다. 이러한 경우 태그 기술 및 페이로드에 관한 정보가 있는 Tag 객체는 대신 ACTION_TECH_DISCOVERED 인텐트 내에 페이로드를 캡슐화합니다.

표 1은 태그 디스패치 시스템이 TNF 및 유형 필드를 MIME 유형 또는 URI에 매핑하는 방법을 설명합니다. 또한 어떤 TNF를 MIME 유형이나 URI에 매핑할 수 없는지도 설명합니다. 이러한 경우 태그 디스패치 시스템은 ACTION_TECH_DISCOVERED로 대체됩니다.

예를 들어 태그 디스패치 시스템은 TNF_ABSOLUTE_URI 유형의 레코드를 발견하면 이 레코드의 가변 길이 유형 필드를 URI에 매핑합니다. 태그 디스패치 시스템은 페이로드와 같은 태그에 관한 다른 정보와 함께 ACTION_NDEF_DISCOVERED 인텐트의 데이터 필드에 이 URI를 캡슐화합니다. 반면 TNF_UNKNOWN 유형의 레코드를 발견하면 대신 태그의 기술을 캡슐화하는 인텐트를 만듭니다.

표 1. 지원되는 TNF 및 매핑

TNF(Type Name Format) 매핑
TNF_ABSOLUTE_URI 유형 필드를 기반으로 하는 URI.
TNF_EMPTY ACTION_TECH_DISCOVERED로 대체됩니다.
TNF_EXTERNAL_TYPE 유형 필드의 URN을 기반으로 하는 URI. URN은 <domain_name>:<service_name>의 축약 형식으로 NDEF 유형 필드에 인코딩됩니다. Android는 이를 vnd.android.nfc://ext/<domain_name>:<service_name> 형식으로 URI에 매핑합니다.
TNF_MIME_MEDIA 유형 필드를 기반으로 하는 MIME 유형.
TNF_UNCHANGED 첫 번째 레코드가 잘못되어 ACTION_TECH_DISCOVERED로 대체됩니다.
TNF_UNKNOWN ACTION_TECH_DISCOVERED로 대체됩니다.
TNF_WELL_KNOWN 유형 필드에서 설정한 RTD(Record Type Definition)에 따라 MIME 유형 또는 URI. 사용 가능한 RTD 및 매핑에 관한 자세한 내용은 표 2를 참조하세요.

표 2. TNF_WELL_KNOWN 및 매핑에서 지원되는 RTD

RTD(Record Type Definition) 매핑
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 태그와 태그의 식별 정보를 캡슐화하는 인텐트를 만든 후 인텐트 필터링에 관심이 있는 애플리케이션에 인텐트를 전송합니다. 둘 이상의 애플리케이션에서 인텐트를 처리할 수 있는 경우 사용자가 활동을 선택할 수 있도록 활동 선택기가 표시됩니다. 태그 디스패치 시스템은 우선순위가 가장 높은 것부터 낮은 것 순으로 세 개의 인텐트를 정의합니다.

  1. ACTION_NDEF_DISCOVERED: 이 인텐트는 NDEF 페이로드가 포함된 태그가 검사될 때와 태그의 유형이 인식될 때 활동을 시작하기 위해 사용됩니다. 이 인텐트는 우선순위가 가장 높으며, 태그 디스패치 시스템은 가능한 경우 항상 다른 인텐트 이전에 이 인텐트로 활동을 시작하려고 합니다.
  2. ACTION_TECH_DISCOVERED: ACTION_NDEF_DISCOVERED 인텐트를 처리하도록 등록된 활동이 없는 경우 태그 디스패치 시스템은 이 인텐트로 애플리케이션을 시작하려고 합니다. 태그에 MIME 유형 또는 URI에 매핑할 수 없는 NDEF 데이터가 포함되어 있거나 태그에 NDEF 데이터가 포함되어 있지 않지만 태그 기술이 알려진 경우 이 인텐트도 직접 시작됩니다(먼저 ACTION_NDEF_DISCOVERED를 시작하지 않음).
  3. ACTION_TAG_DISCOVERED: ACTION_NDEF_DISCOVERED 또는 ACTION_TECH_DISCOVERED 인텐트를 처리할 활동이 없는 경우 이 인텐트가 시작됩니다.

태그 디스패치 시스템의 기본 작동 방법은 다음과 같습니다.

  1. NFC 태그(ACTION_NDEF_DISCOVERED 또는 ACTION_TECH_DISCOVERED)를 파싱할 때 태그 디스패치 시스템에서 만든 인텐트를 사용하여 활동을 시작해 봅니다.
  2. 이 인텐트를 필터링하는 활동이 없는 경우 애플리케이션이 인텐트를 필터링하거나 태그 디스패치 시스템이 가능한 모든 인텐트를 시도할 때까지 우선순위가 다음으로 낮은 인텐트로 활동을 시작해 봅니다(ACTION_TECH_DISCOVERED 또는 ACTION_TAG_DISCOVERED).
  3. 인텐트를 필터링하는 애플리케이션이 없는 경우 아무것도 하지 않습니다.
그림 1. 태그 디스패치 시스템

가능한 경우에는 항상 NDEF 메시지 및 ACTION_NDEF_DISCOVERED 인텐트로 작업합니다. 이 인텐트가 세 가지 중에서 가장 구체적이기 때문입니다. 이 인텐트를 사용하면 다른 두 인텐트보다 더 적절한 시간에 애플리케이션을 시작할 수 있으므로 사용자에게 더 나은 환경이 제공됩니다.

Android manifest에서 NFC 액세스 요청

기기의 NFC 하드웨어에 액세스하고 NFC 인텐트를 제대로 처리하려면 AndroidManifest.xml 파일에서 다음 항목을 선언합니다.

  • NFC 하드웨어에 액세스하기 위한 NFC <uses-permission> 요소.
        <uses-permission android:name="android.permission.NFC" />
        
  • 애플리케이션이 지원할 수 있는 최소 SDK 버전. API 레벨 9는 ACTION_TAG_DISCOVERED를 통해 제한된 태그 디스패치만 지원하며 EXTRA_NDEF_MESSAGES 엑스트라를 통해 NDEF 메시지에만 액세스하도록 허용합니다. 다른 태그 속성 또는 I/O 작업에는 액세스할 수 없습니다. API 레벨 10에는 포그라운드 NDEF 푸시뿐만 아니라 포괄적인 reader/writer 지원도 포함되어 있으며, API 레벨 14는 Android Beam을 사용하여 NDEF 메시지를 다른 기기로 더 쉽게 푸시하는 방법과 NDEF 레코드를 만드는 편리한 추가 방법을 제공합니다.
        <uses-sdk android:minSdkVersion="10"/>
        
  • NFC 하드웨어가 있는 기기에서만 애플리케이션이 Google Play에 표시되도록 하는 uses-feature 요소:
        <uses-feature android:name="android.hardware.nfc" android:required="true" />
        

    애플리케이션이 NFC 기능을 사용하지만 애플리케이션에서 이 기능이 중요하지 않은 경우에는 uses-feature 요소를 생략하고, getDefaultAdapter()null인지 확인하여 런타임 시 NFC 가용성을 확인할 수 있습니다.

NFC 인텐트 필터링

처리하려는 NFC 태그가 검사될 때 애플리케이션을 시작하려면 애플리케이션에서 Android manifest의 NFC 인텐트 한두 개 또는 세 개를 모두 필터링하면 됩니다. 하지만 애플리케이션 시작 시기를 최대한 제어하기 위해 일반적으로 ACTION_NDEF_DISCOVERED 인텐트를 필터링합니다. ACTION_NDEF_DISCOVERED용 애플리케이션 필터가 없거나 페이로드가 NDEF가 아닌 경우 ACTION_TECH_DISCOVERED 인텐트는 ACTION_NDEF_DISCOVERED의 대체입니다. ACTION_TAG_DISCOVERED의 필터링은 대개 필터링할 범주가 너무 일반적입니다. 많은 애플리케이션이 ACTION_TAG_DISCOVERED 전에 ACTION_NDEF_DISCOVERED 또는 ACTION_TECH_DISCOVERED를 필터링할 것이므로 내 애플리케이션이 시작될 가능성이 낮습니다. ACTION_TAG_DISCOVEREDACTION_NDEF_DISCOVERED 또는 ACTION_TECH_DISCOVERED 인텐트를 처리할 다른 애플리케이션이 설치되지 않은 경우 애플리케이션을 필터링하기 위한 마지막 수단으로만 사용할 수 있습니다.

NFC 태그 배포는 다양하며 제어할 수 없는 경우가 많으므로 항상 가능한 것은 아닙니다. 따라서 필요한 경우 다른 두 인텐트로 대체할 수 있습니다. 작성된 태그 및 데이터 유형을 제어할 수 있는 경우 NDEF를 사용하여 태그 형식을 지정하는 것이 좋습니다. 다음 섹션에서는 각 인텐트 유형을 필터링하는 방법을 설명합니다.

ACTION_NDEF_DISCOVERED

ACTION_NDEF_DISCOVERED 인텐트를 필터링하려면 필터링하려는 데이터 유형과 함께 인텐트 필터를 선언합니다. 다음 예에서는 ACTION_NDEF_DISCOVERED MIME 유형으로 text/plain 인텐트를 필터링합니다.

    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain" />
    </intent-filter>
    

다음 예에서는 https://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 인텐트를 필터링하는 경우 tech-list 집합 내에서 활동이 지원하는 기술을 지정하는 XML 리소스 파일을 만들어야 합니다. tech-list 집합이 태그가 지원하는 기술의 하위 집합인 경우 활동이 일치하는 것으로 간주됩니다. 이 집합은 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()에 의해 반환되는 기술의 하위 집합인 경우 활동이 일치하는 것으로 간주됩니다. 이는 일치하는 기술의 ANDOR 의미 체계를 제공합니다. 다음 예는 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>
        <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 인텐트 작업에 관한 자세한 내용은 고급 NFC 문서의 지원되는 태그 기술 작업을 참조하세요.

ACTION_TAG_DISCOVERED

ACTION_TAG_DISCOVERED를 필터링하려면 다음 인텐트 필터를 사용합니다.

<intent-filter>
        <action android:name="android.nfc.action.TAG_DISCOVERED"/>
    </intent-filter>
    

인텐트에서 정보 가져오기

NFC 인텐트로 인해 활동이 시작되는 경우 인텐트에서 검사된 NFC 태그에 관한 정보를 가져올 수 있습니다. 인텐트는 검사된 태그에 따라 다음 추가 항목을 포함할 수 있습니다.

이러한 추가 항목을 가져오려면 NFC 인텐트 중 하나로 활동이 실행되어 태그가 검사되었는지 확인한 다음 인텐트에서 추가 항목을 가져옵니다. 다음 예에서는 ACTION_NDEF_DISCOVERED 인텐트를 확인하고 인텐트 추가 항목에서 NDEF 메시지를 가져옵니다.

Kotlin

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)
        ...
        if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
            intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMessages ->
                val messages: List<NdefMessage> = rawMessages.map { it as NdefMessage }
                // Process the messages array.
                ...
            }
        }
    }
    

자바

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        ...
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
            Parcelable[] rawMessages =
                intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            if (rawMessages != null) {
                NdefMessage[] messages = new NdefMessage[rawMessages.length];
                for (int i = 0; i < rawMessages.length; i++) {
                    messages[i] = (NdefMessage) rawMessages[i];
                }
                // Process the messages array.
                ...
            }
        }
    }
    

또는 페이로드를 포함하고 태그의 기술을 열거할 수 있는 Tag 객체를 인텐트에서 가져올 수 있습니다.

Kotlin

    val tag: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
    

자바

    Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    

일반적인 NDEF 레코드 유형 만들기

이 섹션에서는 NFC 태그에 쓰거나 Android Beam으로 데이터를 보낼 때 사용할 수 있는 일반적인 NDEF 레코드 유형을 만드는 방법을 설명합니다. Android 4.0(API 레벨 14)부터는 createUri() 메서드를 사용하여 URI 레코드를 자동으로 만들 수 있습니다. Android 4.1(API 레벨 16)부터는 createExternal()createMime()을 사용하여 MIME 및 외부 유형 NDEF 레코드를 만들 수 있습니다. NDEF 레코드를 수동으로 만들 때 실수를 피하려면 가능한 한 이러한 도우미 메서드를 사용합니다.

이 섹션에서는 레코드에 해당하는 인텐트 필터를 만드는 방법을 설명합니다. 이러한 모든 NDEF 레코드 예는 태그에 쓰거나 공유하려는 NDEF 메시지의 첫 번째 NDEF 레코드에 있어야 합니다.

TNF_ABSOLUTE_URI

참고: TNF_ABSOLUTE_URI 대신 RTD_URI 유형을 사용하는 것이 좋습니다. 효율성이 더 뛰어나기 때문입니다.

다음과 같은 방법으로 TNF_ABSOLUTE_URI NDEF 레코드를 만들 수 있습니다.

Kotlin

    val uriRecord = ByteArray(0).let { emptyByteArray ->
        NdefRecord(
                TNF_ABSOLUTE_URI,
                "https://developer.android.com/index.html".toByteArray(Charset.forName("US-ASCII")),
                emptyByteArray,
                emptyByteArray
        )
    }
    

자바

    NdefRecord uriRecord = new NdefRecord(
        NdefRecord.TNF_ABSOLUTE_URI ,
        "https://developer.android.com/index.html".getBytes(Charset.forName("US-ASCII")),
        new byte[0], new byte[0]);
    

이전 NDEF 레코드의 인텐트 필터는 다음과 유사합니다.

    <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 레코드를 만들 수 있습니다.

createMime() 메서드 사용:

Kotlin

    val mimeRecord = NdefRecord.createMime(
            "application/vnd.com.example.android.beam",
            "Beam me up, Android".toByteArray(Charset.forName("US-ASCII"))
    )
    

자바

    NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam",
        "Beam me up, Android".getBytes(Charset.forName("US-ASCII")));
    

수동으로 NdefRecord 만들기:

Kotlin

    val mimeRecord = Charset.forName("US-ASCII").let { usAscii ->
        NdefRecord(
                NdefRecord.TNF_MIME_MEDIA,
                "application/vnd.com.example.android.beam".toByteArray(usAscii),
                ByteArray(0),
                "Beam me up, Android!".toByteArray(usAscii)
        )
    }
    

자바

    NdefRecord mimeRecord = new NdefRecord(
        NdefRecord.TNF_MIME_MEDIA ,
        "application/vnd.com.example.android.beam".getBytes(Charset.forName("US-ASCII")),
        new byte[0], "Beam me up, Android!".getBytes(Charset.forName("US-ASCII")));
    

이전 NDEF 레코드의 인텐트 필터는 다음과 유사합니다.

    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="application/vnd.com.example.android.beam" />
    </intent-filter>
    

TNF_WELL_KNOWN with RTD_TEXT

다음과 같은 방법으로 TNF_WELL_KNOWN NDEF 레코드를 만들 수 있습니다.

Kotlin

    fun createTextRecord(payload: String, locale: Locale, encodeInUtf8: Boolean): NdefRecord {
        val langBytes = locale.language.toByteArray(Charset.forName("US-ASCII"))
        val utfEncoding = if (encodeInUtf8) Charset.forName("UTF-8") else Charset.forName("UTF-16")
        val textBytes = payload.toByteArray(utfEncoding)
        val utfBit: Int = if (encodeInUtf8) 0 else 1 shl 7
        val status = (utfBit + langBytes.size).toChar()
        val data = ByteArray(1 + langBytes.size + textBytes.size)
        data[0] = status.toByte()
        System.arraycopy(langBytes, 0, data, 1, langBytes.size)
        System.arraycopy(textBytes, 0, data, 1 + langBytes.size, textBytes.size)
        return NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, ByteArray(0), data)
    }
    

자바

    public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
        byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
        Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
        byte[] textBytes = payload.getBytes(utfEncoding);
        int utfBit = encodeInUtf8 ? 0 : (1 << 7);
        char status = (char) (utfBit + langBytes.length);
        byte[] data = new byte[1 + langBytes.length + textBytes.length];
        data[0] = (byte) status;
        System.arraycopy(langBytes, 0, data, 1, langBytes.length);
        System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);
        NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
        NdefRecord.RTD_TEXT, new byte[0], data);
        return record;
    }
    

이전 NDEF 레코드의 인텐트 필터는 다음과 유사합니다.

    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
    

TNF_WELL_KNOWN with RTD_URI

다음과 같은 방법으로 TNF_WELL_KNOWN NDEF 레코드를 만들 수 있습니다.

createUri(String) 메서드 사용:

Kotlin

    val rtdUriRecord1 = NdefRecord.createUri("http://example.com")
    

자바

    NdefRecord rtdUriRecord1 = NdefRecord.createUri("http://example.com");
    

createUri(Uri) 메서드 사용:

Kotlin

    val rtdUriRecord2 = Uri.parse("http://example.com").let { uri ->
        NdefRecord.createUri(uri)
    }
    

자바

    Uri uri = Uri.parse("http://example.com");
    NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);
    

수동으로 NdefRecord 만들기:

Kotlin

    val uriField = "example.com".toByteArray(Charset.forName("US-ASCII"))
    val payload = ByteArray(uriField.size + 1)                   //add 1 for the URI Prefix
    payload [0] = 0x01                                           //prefixes http://www. to the URI
    System.arraycopy(uriField, 0, payload, 1, uriField.size)     //appends URI to payload
    val rtdUriRecord = NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, ByteArray(0), payload)
    

자바

    byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII"));
    byte[] payload = new byte[uriField.length + 1];              //add 1 for the URI Prefix
    payload[0] = 0x01;                                           //prefixes http://www. to the URI
    System.arraycopy(uriField, 0, payload, 1, uriField.length);  //appends URI to payload
    NdefRecord rtdUriRecord = new NdefRecord(
        NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);
    

이전 NDEF 레코드의 인텐트 필터는 다음과 유사합니다.

    <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 레코드를 만들 수 있습니다.

createExternal() 메서드 사용:

Kotlin

    var payload: ByteArray //assign to your data
    val domain = "com.example" //usually your app's package name
    val type = "externalType"
    val extRecord = NdefRecord.createExternal(domain, type, payload)
    

자바

    byte[] payload; //assign to your data
    String domain = "com.example"; //usually your app's package name
    String type = "externalType";
    NdefRecord extRecord = NdefRecord.createExternal(domain, type, payload);
    

수동으로 NdefRecord 만들기:

Kotlin

    var payload: ByteArray
    ...
    val extRecord = NdefRecord(
            NdefRecord.TNF_EXTERNAL_TYPE,
            "com.example:externalType".toByteArray(Charset.forName("US-ASCII")),
            ByteArray(0),
            payload
    )
    

자바

    byte[] payload;
    ...
    NdefRecord extRecord = new NdefRecord(
        NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType".getBytes(Charset.forName("US-ASCII")),
        new byte[0], payload);
    

이전 NDEF 레코드의 인텐트 필터는 다음과 유사합니다.

    <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="/com.example:externalType"/>
    </intent-filter>
    

Android 구동 기기 및 비 Android 구동 기기 모두를 더 잘 지원하기 위해 더 일반적인 NFC 태그를 배포하려면 TNF_EXTERNAL_TYPE을 사용하세요.

참고: TNF_EXTERNAL_TYPE용 URN의 표준 형식은 urn:nfc:ext:example.com:externalType이지만 NFC Forum RTD 사양에서는 URN의 urn:nfc:ext: 부분을 NDEF 레코드에서 생략해야 한다고 선언합니다. 따라서 도메인(이 예에서는 example.com)과 유형(이 예에서는 externalType)을 콜론으로 구분하여 제공하기만 하면 됩니다. TNF_EXTERNAL_TYPE을 디스패치할 때 Android는 urn:nfc:ext:example.com:externalType URN을 vnd.android.nfc://ext/example.com:externalType URI로 변환하며, 이것이 위 예에서 인텐트 필터가 선언한 내용입니다.

Android 애플리케이션 레코드

Android 4.0(API 레벨 14)에 도입된 Android AAR(Android Application Record)은 NFC 태그를 검사할 때 애플리케이션이 시작될 가능성을 크게 높여줍니다. AAR에는 NDEF 레코드 내에 포함된 애플리케이션의 패키지 이름이 있습니다. Android는 전체 NDEF 메시지에서 AAR을 검색하므로 NDEF 메시지의 NDEF 레코드에 AAR을 추가할 수 있습니다. Android는 AAR을 찾으면 AAR 내의 패키지 이름에 따라 애플리케이션을 시작합니다. 기기에 애플리케이션이 없으면 Google Play가 실행되어 애플리케이션을 다운로드합니다.

다른 애플리케이션이 동일한 인텐트를 필터링하고 배포된 특정 태그를 처리하는 것을 방지하려는 경우 AAR이 유용합니다. AAR은 패키지 이름 제약 조건 때문에 애플리케이션 수준에서만 지원되며 인텐트 필터링처럼 활동 수준에서는 지원되지 않습니다. 활동 수준에서 인텐트를 처리하려면 인텐트 필터를 사용합니다.

태그에 AAR이 포함된 경우 태그 디스패치 시스템은 다음과 같은 방식으로 디스패치합니다.

  1. 평상시처럼 인텐트 필터를 사용하여 활동을 시작해 봅니다. 인텐트와 일치하는 활동이 AAR과도 일치하는 경우 활동을 시작합니다.
  2. 인텐트를 필터링하는 활동이 AAR과 일치하지 않거나, 여러 활동이 인텐트를 처리할 수 있거나, 인텐트를 처리할 활동이 없는 경우 AAR이 지정한 애플리케이션을 시작합니다.
  3. AAR로 시작할 수 있는 애플리케이션이 없는 경우 Google Play로 이동하여 AAR을 기반으로 애플리케이션을 다운로드합니다.

참고: AAR과 인텐트 디스패치 시스템을 포그라운드 디스패치 시스템으로 재정의할 수 있습니다. 그러면 NFC 태그가 검색될 때 포그라운드 활동이 우선순위를 갖게 됩니다. 이 방법을 사용할 경우 AAR 및 인텐트 디스패치 시스템을 재정의하려면 활동이 포그라운드에 있어야 합니다.

AAR이 포함되지 않은 검사된 태그를 필터링하려는 경우 평상시처럼 인텐트 필터를 선언할 수 있습니다. 이 방법은 애플리케이션이 AAR이 없는 다른 태그에 관심이 있는 경우에 유용합니다. 예를 들어 직접 배포한 독점 태그와 타사에서 배포한 일반 태그를 애플리케이션이 모두 처리하도록 하고자 하는 경우입니다. AAR은 Android 4.0 이상의 기기에만 해당되므로 태그를 배포할 때 AAR과 MIME 유형/URI의 조합을 사용하면 가장 광범위한 기기를 지원할 수 있습니다. 또한 NFC 태그를 배포할 때 대부분의 기기(Android 구동 기기 및 기타 기기)를 지원할 수 있도록 NFC 태그를 작성하는 방법에 관해 생각해 보세요. 애플리케이션을 더 쉽게 구별할 수 있도록 비교적 고유한 MIME 유형 또는 URI를 정의하면 됩니다.

Android는 AAR, createApplicationRecord()를 생성하는 간단한 API를 제공합니다. NdefMessage에 AAR을 삽입하기만 하면 됩니다. AAR이 NdefMessage의 유일한 레코드가 아니라면 NdefMessage의 첫 번째 레코드를 사용하지 않는 것이 좋습니다. 왜냐하면 Android 시스템이 NdefMessage의 첫 번째 레코드를 확인하여 애플리케이션 필터링을 위한 인텐트를 만드는 데 사용되는 태그의 MIME 유형 또는 URI를 확인하기 때문입니다. 다음 코드는 AAR을 만드는 방법을 보여줍니다.

Kotlin

    val msg = NdefMessage(
            arrayOf(
                    ...,
                    NdefRecord.createApplicationRecord("com.example.android.beam")
            )
    )
    

자바

    NdefMessage msg = new NdefMessage(
            new NdefRecord[] {
                ...,
                NdefRecord.createApplicationRecord("com.example.android.beam")}
            );
    )
    

NDEF 메시지를 다른 기기와 공유

Android Beam을 사용하면 두 대의 Android 구동 기기 간에 간편하게 P2P 데이터를 교환할 수 있습니다. 데이터를 다른 기기와 공유하려는 애플리케이션은 포그라운드에 있어야 하며 데이터를 수신하는 기기는 잠겨 있지 않아야 합니다. 공유 기기가 수신 기기에 충분히 근접하게 되면 공유 기기에 '공유하기' UI가 표시됩니다. 그런 다음 수신 기기와 메시지를 공유할지 여부를 선택할 수 있습니다.

참고: API 레벨 10에서는 Android Beam과 유사한 기능을 제공하는 포그라운드 NDEF 푸시 기능이 제공되었습니다. 이러한 API는 이제 지원 중단되었지만 이전 기기를 지원하는 데 사용할 수 있습니다. 자세한 내용은 enableForegroundNdefPush()를 참조하세요.

다음 두 가지 메서드 중 하나를 호출하여 애플리케이션에서 Android Beam을 사용하도록 설정할 수 있습니다.

  • setNdefPushMessage(): NdefMessage를 수락하여 공유할 메시지로 설정합니다. 두 기기가 근접해질 때 자동으로 메시지를 공유합니다.
  • setNdefPushMessageCallback(): 기기가 데이터를 공유할 범위에 있을 때 호출되는 createNdefMessage()를 포함하는 콜백을 수락합니다. 콜백을 사용하면 필요할 경우에만 NDEF 메시지를 만들 수 있습니다.

활동은 한 번에 하나의 NDEF 메시지만 푸시할 수 있으므로 setNdefPushMessageCallback()setNdefPushMessage()보다 우선순위를 갖습니다. Android Beam을 사용하려면 다음 일반 가이드라인을 충족해야 합니다.

  • 데이터를 공유하는 활동은 포그라운드 상태여야 합니다. 두 기기 모두 화면 잠금이 해제되어 있어야 합니다.
  • 공유하는 데이터를 NdefMessage 객체에서 캡슐화해야 합니다.
  • 공유된 데이터를 수신하는 NFC 기기는 com.android.npp NDEF 푸시 프로토콜 또는 NFC 포럼의 SNEP(Simple NDEF Exchange Protocol)를 지원해야 합니다. API 레벨 9(Android 2.3)에서 API 레벨 13(Android 3.2)까지의 기기에는 com.android.npp 프로토콜이 필요합니다. API 레벨 14(Android 4.0) 이상에서는 com.android.npp 및 SNEP가 모두 필요합니다.

참고: 활동이 Android Beam을 사용 설정하고 포그라운드 상태인 경우 표준 인텐트 디스패치 시스템이 사용 중지됩니다. 하지만 활동이 포그라운드 디스패치도 사용 설정하면 포그라운드 디스패칭에서 설정된 인텐트 필터와 일치하는 태그를 계속해서 검사할 수 있습니다.

Android Beam을 사용 설정하려면 다음과 같이 하세요.

  1. 다른 기기에 푸시할 NdefRecord가 포함된 NdefMessage를 만듭니다.
  2. NdefMessagesetNdefPushMessage()를 호출하거나 활동의 onCreate() 메서드에서 NfcAdapter.CreateNdefMessageCallback 객체를 전달하는 setNdefPushMessageCallback을 호출합니다. 이러한 메서드에는 활성화할 기타 활동의 목록(선택 사항)과 함께 Android Beam으로 사용 설정하려는 활동이 하나 이상 필요합니다.

    두 기기가 통신 범위 내에 있을 때 활동이 항상 같은 NDEF 메시지만 푸시해야 하는 경우 일반적으로 setNdefPushMessage()를 사용합니다. 애플리케이션이 현재의 컨텍스트에 관심이 있고 사용자의 작업 내용에 따라 NDEF 메시지를 푸시하고자 할 경우 setNdefPushMessageCallback을 사용합니다.

다음 샘플에서는 간단한 활동이 활동의 onCreate() 메서드에서 NfcAdapter.CreateNdefMessageCallback을 호출하는 방법을 보여줍니다(전체 샘플은 AndroidBeamDemo 참조). 이 예에는 MIME 레코드를 만드는 데 도움이 되는 메서드도 있습니다.

Kotlin

    package com.example.android.beam

    import android.app.Activity
    import android.content.Intent
    import android.nfc.NdefMessage
    import android.nfc.NdefRecord
    import android.nfc.NfcAdapter
    import android.nfc.NfcAdapter.CreateNdefMessageCallback
    import android.nfc.NfcEvent
    import android.os.Bundle
    import android.os.Parcelable
    import android.widget.TextView
    import android.widget.Toast
    import java.nio.charset.Charset

    class Beam : Activity(), NfcAdapter.CreateNdefMessageCallback {

        private var nfcAdapter: NfcAdapter? = null
        private lateinit var textView: TextView

        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.main)
            textView = findViewById(R.id.textView)
            // Check for available NFC Adapter
            nfcAdapter = NfcAdapter.getDefaultAdapter(this)
            if (nfcAdapter == null) {
                Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show()
                finish()
                return
            }
            // Register callback
            nfcAdapter?.setNdefPushMessageCallback(this, this)
        }

        override fun createNdefMessage(event: NfcEvent): NdefMessage {
            val text = "Beam me up, Android!\n\n" +
                    "Beam Time: " + System.currentTimeMillis()
            return NdefMessage(
                    arrayOf(
                            createMime("application/vnd.com.example.android.beam", text.toByteArray())
                    )
                    /**
                     * The Android Application Record (AAR) is commented out. When a device
                     * receives a push with an AAR in it, the application specified in the AAR
                     * is guaranteed to run. The AAR overrides the tag dispatch system.
                     * You can add it back in to guarantee that this
                     * activity starts when receiving a beamed message. For now, this code
                     * uses the tag dispatch system.
                     *///,NdefRecord.createApplicationRecord("com.example.android.beam")
            )
        }

        override fun onResume() {
            super.onResume()
            // Check to see that the Activity started due to an Android Beam
            if (NfcAdapter.ACTION_NDEF_DISCOVERED == intent.action) {
                processIntent(intent)
            }
        }

        override fun onNewIntent(intent: Intent) {
            // onResume gets called after this to handle the intent
            setIntent(intent)
        }

        /**
         * Parses the NDEF Message from the intent and prints to the TextView
         */
        private fun processIntent(intent: Intent) {
            textView = findViewById(R.id.textView)
            // only one message sent during the beam
            intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)?.also { rawMsgs ->
                (rawMsgs[0] as NdefMessage).apply {
                    // record 0 contains the MIME type, record 1 is the AAR, if present
                    textView.text = String(records[0].payload)
                }
            }
        }
    }
    

자바

    package com.example.android.beam;

    import android.app.Activity;
    import android.content.Intent;
    import android.nfc.NdefMessage;
    import android.nfc.NdefRecord;
    import android.nfc.NfcAdapter;
    import android.nfc.NfcAdapter.CreateNdefMessageCallback;
    import android.nfc.NfcEvent;
    import android.os.Bundle;
    import android.os.Parcelable;
    import android.widget.TextView;
    import android.widget.Toast;
    import java.nio.charset.Charset;

    public class Beam extends Activity implements CreateNdefMessageCallback {
        NfcAdapter nfcAdapter;
        TextView textView;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            TextView textView = (TextView) findViewById(R.id.textView);
            // Check for available NFC Adapter
            nfcAdapter = NfcAdapter.getDefaultAdapter(this);
            if (nfcAdapter == null) {
                Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
                finish();
                return;
            }
            // Register callback
            nfcAdapter.setNdefPushMessageCallback(this, this);
        }

        @Override
        public NdefMessage createNdefMessage(NfcEvent event) {
            String text = ("Beam me up, Android!\n\n" +
                    "Beam Time: " + System.currentTimeMillis());
            NdefMessage msg = new NdefMessage(
                    new NdefRecord[] { createMime(
                            "application/vnd.com.example.android.beam", text.getBytes())
             /**
              * The Android Application Record (AAR) is commented out. When a device
              * receives a push with an AAR in it, the application specified in the AAR
              * is guaranteed to run. The AAR overrides the tag dispatch system.
              * You can add it back in to guarantee that this
              * activity starts when receiving a beamed message. For now, this code
              * uses the tag dispatch system.
              */
              //,NdefRecord.createApplicationRecord("com.example.android.beam")
            });
            return msg;
        }

        @Override
        public void onResume() {
            super.onResume();
            // Check to see that the Activity started due to an Android Beam
            if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
                processIntent(getIntent());
            }
        }

        @Override
        public void onNewIntent(Intent intent) {
            // onResume gets called after this to handle the intent
            setIntent(intent);
        }

        /**
         * Parses the NDEF Message from the intent and prints to the TextView
         */
        void processIntent(Intent intent) {
            textView = (TextView) findViewById(R.id.textView);
            Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
                    NfcAdapter.EXTRA_NDEF_MESSAGES);
            // only one message sent during the beam
            NdefMessage msg = (NdefMessage) rawMsgs[0];
            // record 0 contains the MIME type, record 1 is the AAR, if present
            textView.setText(new String(msg.getRecords()[0].getPayload()));
        }
    }
    

이 코드는 삭제할 수 있는 AAR을 주석 처리합니다. AAR을 사용 설정하면 AAR에 지정된 애플리케이션이 항상 Android Beam 메시지를 수신합니다. 애플리케이션이 없는 경우 Google Play가 시작되어 애플리케이션을 다운로드합니다. 따라서 AAR을 사용하는 경우 Android 4.0 기기 이상에서 기술적으로 다음 인텐트 필터가 필요하지 않습니다.

    <intent-filter>
      <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
      <category android:name="android.intent.category.DEFAULT"/>
      <data android:mimeType="application/vnd.com.example.android.beam"/>
    </intent-filter>
    

이 인텐트 필터를 사용하면 NFC 태그를 검사하거나 com.example.android.beam 유형의 AAR로 Android Beam을 수신할 때 또는 NDEF 형식의 메시지에 application/vnd.com.example.android.beam 유형의 MIME 레코드가 포함되었을 때 애플리케이션을 시작할 수 있습니다.

AAR이 애플리케이션의 시작 또는 다운로드를 보장하더라도 인텐트 필터를 사용하는 것이 좋습니다. AAR에 의해 지정된 패키지 내에서 항상 기본 활동을 시작하는 대신 애플리케이션에서 원하는 활동을 시작할 수 있기 때문입니다. AAR에는 활동 수준의 세분성이 없습니다. 또한 일부 Android 구동 기기는 AAR을 지원하지 않기 때문에 만약의 경우에 대비하여 NDEF 메시지의 첫 번째 NDEF 레코드에 식별 정보를 삽입하고 필터링해야 합니다. 레코드를 만드는 방법에 관한 자세한 내용은 일반적인 유형의 NDEF 레코드 만들기를 참조하세요.