NFC の基本

このドキュメントでは、Android で行う基本的な NFC タスクについて説明します。NDEF メッセージの形式で NFC データを送受信する方法と、これらの機能をサポートする Android フレームワーク API について説明します。NDEF 以外のデータの処理方法など、詳細なトピックについては、高度な NFC をご覧ください。

NFC タグからの NDEF データの読み取りは、タグ ディスパッチ システムで処理されます。このシステムは、検出された NFC タグを分析し、データを適切に分類して、分類されたデータに関連したアプリケーションを起動します。スキャンされた NFC タグを処理するアプリケーションでインテント フィルタを宣言して、データの処理をリクエストできます。

タグ ディスパッチ システム

Android デバイスは通常、デバイスの設定メニューで NFC が無効になっていない限り、画面のロックが解除されたときに NFC タグを探します。Android デバイスが NFC タグを検出した場合、ユーザーに使用するアプリケーションを確認せずに、最も適切なアクティビティにインテントを処理させることが、期待される動作です。デバイスは NFC タグを非常に短い範囲でスキャンするため、ユーザーが手動でアクティビティを選択しようとすると、デバイスをタグから遠ざけ、接続が切断される可能性があります。 選択ダイアログが表示されないようにするには、アクティビティで重要な NFC タグのみを処理するようにアクティビティを開発する必要があります。

この目的を達成できるように、Android には特別なタグ ディスパッチ システムが用意されています。このシステムは、スキャンされた NFC タグを分析して解析し、スキャンしたデータを必要とするアプリを探します。これは次の方法で行います。

  1. NFC タグを解析して、タグ内のデータ ペイロードを識別する MIME タイプまたは URI を特定します。
  2. MIME タイプまたは URI、およびペイロードをインテントにカプセル化します。これらの最初 2 つの手順は、NFC タグが MIME タイプと URI にマッピングされる仕組みで説明します。
  3. インテントに基づいてアクティビティを開始します。これについては、NFC タグがアプリケーションにディスパッチされる仕組みをご覧ください。

NFC タグが MIME タイプと URI にマッピングされる仕組み

NFC アプリの作成を開始する前に、さまざまな種類の NFC タグ、タグ ディスパッチ システムが NFC タグを解析する方法、NDEF メッセージを検出したときにタグ ディスパッチ システムが行う特別な処理について理解しておくことが重要です。NFC タグは幅広いテクノロジーに対応しており、さまざまな方法でデータを書き込むことができます。Android は NFC フォーラムで定義されている NDEF 標準規格を最大限にサポートしています。

NDEF データは、1 つまたは複数のレコード(NdefRecord)を含むメッセージ(NdefMessage)内にカプセル化されます。各 NDEF レコードは、作成するレコードタイプの仕様に従って適切な形式にする必要があります。Android では、NDEF データを含まない他のタイプのタグもサポートしています。これらのタグは、android.nfc.tech パッケージ内のクラスを使用して操作できます。これらの技術の詳細については、高度な NFC のトピックをご覧ください。このような他の種類のタグを処理する場合は、独自のプロトコル スタックを作成してタグと通信する必要があります。そのため、可能な限り NDEF を使用して、開発を容易にし、Android デバイスを最大限にサポートすることをおすすめします。

注: 完全な 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)を指定します。有効な 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 にマッピングする方法を示します。また、MIME タイプまたは URI にマッピングできない TNF についても説明します。このような場合、タグ ディスパッチ システムは ACTION_TECH_DISCOVERED にフォールバックします。

たとえば、タグ ディスパッチ システムが TNF_ABSOLUTE_URI タイプのレコードを検出した場合、そのレコードの可変長タイプ フィールドを URI にマッピングします。タグ ディスパッチ システムは、その URI をペイロードなどのタグに関する他の情報とともに、ACTION_NDEF_DISCOVERED インテントのデータ フィールドにカプセル化します。一方、TNF_UNKNOWN タイプのレコードが見つかった場合は、代わりにタグのテクノロジーをカプセル化するインテントを作成します。

表 1. サポートされている TNF とそのマッピング

Type Name Format(TNF) マッピング
TNF_ABSOLUTE_URI タイプ フィールドに基づく URI。
TNF_EMPTY ACTION_TECH_DISCOVERED にフォールバックします。
TNF_EXTERNAL_TYPE タイプ フィールドの URN に基づく URI。URN は NDEF タイプ フィールドに短縮形式(<domain_name>:<service_name>)でエンコードされます。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)に応じた MIME タイプまたは URI。利用可能な RTD とそのマッピングについて詳しくは、表 2 をご覧ください。

表 2. TNF_WELL_KNOWN でサポートされている RTD とそのマッピング

レコードタイプ定義(RTD) マッピング
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 タグとその識別情報をカプセル化するインテントの作成を完了すると、インテントをフィルタする関連アプリケーションにインテントを送信します。複数のアプリケーションがインテントを処理できる場合は、選択ダイアログが表示されるため、ユーザーがアクティビティを選択できます。タグ ディスパッチ システムは、3 つのインテントを定義します。このインテントは、優先度の高い順にリストされます。

  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 インテントを処理します。これは、3 つの中で最も具体的であるためです。このインテントを使用すると、他の 2 つのインテントよりも適切なタイミングでアプリケーションを起動できるため、ユーザーのエクスペリエンスが向上します。

Android マニフェストで 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 プッシュ機能があります。API レベル 14 には、NDEF レコードを作成するための便利な追加メソッドがあります。
    <uses-sdk android:minSdkVersion="10"/>
    
  • uses-feature 要素: NFC ハードウェアを備えたデバイスでのみ、アプリが Google Play に表示されます。
    <uses-feature android:name="android.hardware.nfc" android:required="true" />
    

    アプリで NFC 機能を使用しているが、その機能がアプリにとって重要でない場合は、uses-feature 要素を省略し、実行時に getDefaultAdapter()null かどうかを確認して NFC が利用可能かどうかを確認します。

NFC インテントのフィルタ

処理する NFC タグのスキャン時にアプリを起動するには、Android マニフェストで NFC インテントの 1 つ、2 つ、または 3 つすべてをフィルタします。ただし、通常は、アプリケーションの起動タイミングを最大限に制御するために、ACTION_NDEF_DISCOVERED インテントをフィルタする必要があります。ACTION_TECH_DISCOVERED インテントは、ACTION_NDEF_DISCOVERED をフィルタしているアプリケーションがない場合、またはペイロードが NDEF でない場合の ACTION_NDEF_DISCOVERED のフォールバックです。通常、ACTION_TAG_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 インテントをフィルタするには、フィルタ対象のデータタイプとともにインテント フィルタを宣言します。MIME タイプが text/plainACTION_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>

次の例では、URI を https://developer.android.com/index.html の形式でフィルタしています。

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
   <data android:scheme="https"
              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 をサポートしている場合、アクティビティを一致させるには、1 つ、2 つ、または 3 つすべてのテクノロジー(他のものは含めない)を tech-list セットで指定する必要があります。

次の例では、テクノロジーをすべて定義しています。NFC タグでサポートされていないものは削除する必要があります。このファイル(名前は自由に指定できます)を <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 セットは個別に扱われ、getTechList() で返されるテクノロジーのサブセットに相当する tech-list セットが 1 つでも存在する場合、アクティビティは一致すると見なされます。これにより、テクノロジーのマッチングに 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 タグに関する情報をインテントから取得できます。インテントには、スキャンされたタグに応じて次の EXTRA 項目が含まれます。

  • EXTRA_TAG(必須): スキャンされたタグを表す Tag オブジェクト。
  • EXTRA_NDEF_MESSAGES(省略可): タグからパースされた NDEF メッセージの配列。ACTION_NDEF_DISCOVERED インテントでは、このエクストラは必須です。
  • EXTRA_ID(任意): タグの低レベル ID。

これらの EXTRA を取得するには、アクティビティが NFC インテントの 1 つで起動されたかどうかを確認し、タグがスキャンされたことを確認してから、インテントから EXTRA を取得します。ACTION_NDEF_DISCOVERED インテントを確認し、インテントの EXTRA から 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.
            ...
        }
    }
}

Java

@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)

Java

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

一般的なタイプの NDEF レコードを作成する

ここでは、NFC タグへの書き込みに役立つ、一般的なタイプの NDEF レコードを作成する方法について説明します。Android 4.0(API レベル 14)以降では、URI レコードの自動作成に createUri() メソッドを使用できます。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
    )
}

Java

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="https"
        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"))
)

Java

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)
    )
}

Java

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(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)
}

Java

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(RTD_URI)

TNF_WELL_KNOWN NDEF レコードは次の方法で作成できます。

createUri(String) メソッドを使用:

Kotlin

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

Java

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

createUri(Uri) メソッドを使用:

Kotlin

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

Java

Uri uri = Uri.parse("https://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 https://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)

Java

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 https://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="https"
        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)

Java

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
)

Java

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>

TNF_EXTERNAL_TYPE を使用すると、より一般的な NFC タグをデプロイし、Android デバイスと Android 以外のデバイスの両方をより適切にサポートできます。

: TNF_EXTERNAL_TYPE の URN の標準形式は urn:nfc:ext:example.com:externalType ですが、NFC フォーラムの 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 Application Record(AAR)により、NFC タグのスキャン時にアプリケーションが起動される確実性が向上します。AAR には、NDEF レコードに埋め込まれたアプリのパッケージ名があります。Android は NDEF メッセージ全体で AAR を検索するため、NDEF メッセージの任意の NDEF レコードに AAR を追加できます。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 タグをデプロイする際は、NFC タグの書き込み方法を検討して、ほとんどのデバイス(Android デバイスやその他のデバイス)への対応を可能にしてください。これを行うには、重複が比較的生じにくい MIME タイプや URI を定義して、アプリケーションが識別しやすいようにします。

Android は AAR を作成するシンプルな API createApplicationRecord() を提供します。AAR を NdefMessage の任意の場所に埋め込むだけです。AAR が NdefMessage 内の唯一のレコードでない限り、NdefMessage の最初のレコードを使用する必要はありません。これは、Android システムが NdefMessage の最初のレコードをチェックして、タグの MIME タイプまたは URI(アプリケーションがフィルタするインテントの作成に使用されます)を決定するためです。AAR を作成するコードは次のとおりです。

Kotlin

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

Java

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