نمای کلی پیشرفته NFC

این سند موضوعات پیشرفته NFC را شرح می‌دهد، مانند کار با فناوری‌های مختلف برچسب، نوشتن روی برچسب‌های NFC، و ارسال پیش‌زمینه، که به یک برنامه در پیش‌زمینه اجازه می‌دهد تا اهداف را مدیریت کند، حتی زمانی که برنامه‌های دیگر برای همان اهداف فیلتر می‌کنند.

کار با فناوری‌های برچسب پشتیبانی‌شده

هنگام کار با برچسب‌های NFC و دستگاه‌های مجهز به Android، قالب اصلی که برای خواندن و نوشتن داده‌ها روی برچسب‌ها استفاده می‌کنید NDEF است. وقتی دستگاهی برچسبی را با داده‌های NDEF اسکن می‌کند، Android از تجزیه پیام و ارائه آن در NdefMessage درصورت امکان پشتیبانی می‌کند. بااین‌حال، مواردی وجود دارد که برچسبی را اسکن می‌کنید که حاوی داده‌های NDEF نیست یا داده‌های NDEF نمی‌توانند به نوع MIME یا URI نگاشت شوند. در این موارد، باید ارتباط را مستقیماً با برچسب باز کنید و با پروتکل خودتان (در بایت‌های خام) در آن بخوانید و بنویسید. ‫Android با بسته android.nfc.tech که در جدول ۱ شرح داده شده است، پشتیبانی عمومی برای این موارد استفاده ارائه می‌دهد. می‌توانید از روش getTechList() برای تعیین فناوری‌های پشتیبانی‌شده توسط برچسب استفاده کنید و شیء TagTechnology مربوطه را با یکی از کلاس‌های ارائه‌شده توسط android.nfc.tech ایجاد کنید

جدول ۱. فناوری‌های برچسب پشتیبانی‌شده

کلاس شرح
TagTechnology میانایی که همه کلاس‌های فناوری برچسب باید پیاده‌سازی کنند.
NfcA دسترسی به ویژگی‌های NFC-A (ISO 14443-3A) و عملیات ورودی/خروجی را فراهم می‌کند.
NfcB دسترسی به ویژگی‌های NFC-B (ISO 14443-3B) و عملیات ورودی/خروجی را فراهم می‌کند.
NfcF دسترسی به ویژگی‌های NFC-F (JIS 6319-4) و عملیات ورودی/خروجی را فراهم می‌کند.
NfcV دسترسی به ویژگی‌های NFC-V (ISO 15693) و عملیات ورودی/خروجی را فراهم می‌کند.
IsoDep دسترسی به ویژگی‌های ISO-DEP (ISO 14443-4) و عملیات ورودی/خروجی را فراهم می‌کند.
Ndef دسترسی به داده‌های NDEF و عملیات روی برچسب‌های NFC را که به‌عنوان NDEF قالب‌بندی شده‌اند فراهم می‌کند.
NdefFormatable عملیات قالب‌بندی را برای برچسب‌هایی که ممکن است قابل‌قالب‌بندی NDEF باشند ارائه می‌دهد.

دستگاه‌های مجهز به Android ملزم به پشتیبانی از فناوری‌های برچسب زیر نیستند.

جدول ۲. فناوری‌های برچسب پشتیبانی‌شده اختیاری

کلاس شرح
MifareClassic اگر این دستگاه Android از MIFARE پشتیبانی کند، دسترسی به ویژگی‌های MIFARE Classic و عملیات ورودی/خروجی را فراهم می‌کند.
MifareUltralight اگر این دستگاه Android از MIFARE پشتیبانی کند، دسترسی به ویژگی‌های MIFARE Ultralight و عملیات ورودی/خروجی را فراهم می‌کند.

کار با فناوری‌های برچسب و هدف ACTION_TECH_DISCOVERED

وقتی دستگاهی برچسبی را اسکن می‌کند که داده‌های NDEF دارد اما نمی‌تواند به MIME یا URI نگاشت شود، سیستم ارسال برچسب سعی می‌کند فعالیتی را با هدف ACTION_TECH_DISCOVERED شروع کند. وقتی برچسبی با داده‌های غیرNDEF اسکن می‌شود، از ACTION_TECH_DISCOVERED نیز استفاده می‌شود. داشتن این جایگزین به شما امکان می‌دهد مستقیماً با داده‌های روی برچسب کار کنید اگر سیستم ارسال برچسب نتواند آن را برای شما تجزیه کند. مراحل اصلی هنگام کار با فناوری‌های برچسب به شرح زیر است:

  1. فیلتر کردن برای هدف ACTION_TECH_DISCOVERED که فناوری‌های برچسبی را که می‌خواهید مدیریت کنید مشخص می‌کند. برای اطلاعات بیشتر، به فیلتر کردن برای هدف‌های NFC مراجعه کنید. به‌طور کلی، سیستم ارسال برچسب سعی می‌کند وقتی پیام NDEF نمی‌تواند به نوع MIME یا URI نگاشت شود، یا اگر برچسب اسکن‌شده حاوی داده‌های NDEF نباشد، هدف ACTION_TECH_DISCOVERED را شروع کند. برای اطلاعات بیشتر درباره نحوه تعیین این موضوع، سیستم ارسال برچسب را ببینید.
  2. وقتی برنامه‌تان هدف را دریافت می‌کند، شیء Tag را از هدف دریافت کنید:

    کاتلین

    var tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)

    جاوا

    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
  3. با فراخوانی یکی از روش‌های کارخانه get کلاس‌ها در بسته android.nfc.tech، نمونه‌ای از TagTechnology را دریافت کنید. می‌توانید با فراخوانی getTechList() قبل‌از فراخوانی روش کارخانه get، فناوری‌های پشتیبانی‌شده برچسب را فهرست کنید. برای مثال، برای دریافت نمونه‌ای از MifareUltralight از Tag، کارهای زیر را انجام دهید:

    کاتلین

    MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))

    جاوا

    MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));

خواندن و نوشتن در برچسب‌ها

خواندن و نوشتن در برچسب NFC شامل دریافت برچسب از قصد و باز کردن ارتباط با برچسب است. باید پشته پروتکل خودتان را برای خواندن و نوشتن داده‌ها در برچسب تعریف کنید. بااین‌حال، به‌خاطر داشته باشید که هنگام کار مستقیم با برچسب، همچنان می‌توانید داده‌های NDEF را بخوانید و بنویسید. اینکه چگونه می‌خواهید چیزها را ساختاربندی کنید به شما بستگی دارد. مثال زیر نحوه کار با برچسب MIFARE Ultralight را نشان می‌دهد.

کاتلین

package com.example.android.nfc
import android.nfc.Tag
import android.nfc.tech.MifareUltralight
import java.io.IOException
import java.nio.charset.Charset

class MifareUltralightTagTester {

    fun writeTag(tag: Tag, tagText: String) {
        MifareUltralight.get(tag)?.use { ultralight ->
            ultralight.connect()
            Charset.forName("US-ASCII").also { usAscii ->
                ultralight.writePage(4, "abcd".toByteArray(usAscii))
                ultralight.writePage(5, "efgh".toByteArray(usAscii))
                ultralight.writePage(6, "ijkl".toByteArray(usAscii))
                ultralight.writePage(7, "mnop".toByteArray(usAscii))
            }
        }
    }

    fun readTag(tag: Tag): String? {
        return MifareUltralight.get(tag)?.use { mifare ->
            mifare.connect()
            val payload = mifare.readPages(4)
            String(payload, Charset.forName("US-ASCII"))
        }
    }
}

جاوا

package com.example.android.nfc;

import android.nfc.Tag;
import android.nfc.tech.MifareUltralight;
import android.util.Log;
import java.io.IOException;
import java.nio.charset.Charset;

public class MifareUltralightTagTester {

    private static final String TAG = MifareUltralightTagTester.class.getSimpleName();

    public void writeTag(Tag tag, String tagText) {
        MifareUltralight ultralight = MifareUltralight.get(tag);
        try {
            ultralight.connect();
            ultralight.writePage(4, "abcd".getBytes(Charset.forName("US-ASCII")));
            ultralight.writePage(5, "efgh".getBytes(Charset.forName("US-ASCII")));
            ultralight.writePage(6, "ijkl".getBytes(Charset.forName("US-ASCII")));
            ultralight.writePage(7, "mnop".getBytes(Charset.forName("US-ASCII")));
        } catch (IOException e) {
            Log.e(TAG, "IOException while writing MifareUltralight...", e);
        } finally {
            try {
                ultralight.close();
            } catch (IOException e) {
                Log.e(TAG, "IOException while closing MifareUltralight...", e);
            }
        }
    }

    public String readTag(Tag tag) {
        MifareUltralight mifare = MifareUltralight.get(tag);
        try {
            mifare.connect();
            byte[] payload = mifare.readPages(4);
            return new String(payload, Charset.forName("US-ASCII"));
        } catch (IOException e) {
            Log.e(TAG, "IOException while reading MifareUltralight message...", e);
        } finally {
            if (mifare != null) {
               try {
                   mifare.close();
               }
               catch (IOException e) {
                   Log.e(TAG, "Error closing tag...", e);
               }
            }
        }
        return null;
    }
}

استفاده از سیستم ارسال پیش‌زمینه

سیستم ارسال پیش‌زمینه به یک فعالیت اجازه می‌دهد تا یک intent را رهگیری کند و ادعا کند اولویت نسبت به سایر فعالیت‌هایی که همان intent را انجام می‌دهند. استفاده از این سیستم شامل ساخت چند ساختار داده برای سیستم Android است تا بتواند هدف‌های مناسب را به برنامه شما ارسال کند. برای فعال کردن سیستم ارسال پیش‌زمینه:

  1. کد زیر را در روش onCreate() فعالیتتان اضافه کنید:
    1. شیء PendingIntent تغییرپذیری ایجاد کنید تا سیستم Android بتواند آن را با جزئیات برچسب هنگام اسکن شدن پر کند.

      کاتلین

      val intent = Intent(this, javaClass).apply {
          addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
      }
      var pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent,
              PendingIntent.FLAG_MUTABLE)

      جاوا

      PendingIntent pendingIntent = PendingIntent.getActivity(
          this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),
          PendingIntent.FLAG_MUTABLE);
    2. فیلترهای قصد را برای رسیدگی به قصدهایی که می‌خواهید رهگیری کنید اعلام کنید. سیستم ارسال پیش‌زمینه، فیلترهای قصد مشخص‌شده را با قصدی که هنگام اسکن برچسب توسط دستگاه دریافت می‌شود بررسی می‌کند. اگر مطابقت داشته باشد، برنامه شما قصد را مدیریت می‌کند. اگر مطابقت نداشته باشد، سیستم ارسال پیش‌زمینه به سیستم ارسال هدف برمی‌گردد. مشخص کردن آرایه null از فیلترهای قصد و فیلترهای فناوری مشخص می‌کند که می‌خواهید همه برچسب‌هایی را که به قصد TAG_DISCOVERED برمی‌گردند فیلتر کنید. تکه‌کد زیر همه انواع MIME را برای NDEF_DISCOVERED مدیریت می‌کند. فقط باید مواردی را که نیاز دارید مدیریت کنید.

      کاتلین

      val ndef = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED).apply {
          try {
              addDataType("*/*")    /* Handles all MIME based dispatches.
                                       You should specify only the ones that you need. */
          } catch (e: IntentFilter.MalformedMimeTypeException) {
              throw RuntimeException("fail", e)
          }
      }
      
      intentFiltersArray = arrayOf(ndef)

      جاوا

      IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
          try {
              ndef.addDataType("*/*");    /* Handles all MIME based dispatches.
                                             You should specify only the ones that you need. */
          }
          catch (MalformedMimeTypeException e) {
              throw new RuntimeException("fail", e);
          }
         intentFiltersArray = new IntentFilter[] {ndef, };
    3. آرایه‌ای از فناوری‌های برچسب را که برنامه‌تان می‌خواهد مدیریت کند راه‌اندازی کنید. برای دریافت کلاس فناوری‌ای که می‌خواهید پشتیبانی کنید، روش Object.class.getName() را فراخوانی کنید.

      کاتلین

      techListsArray = arrayOf(arrayOf<String>(NfcF::class.java.name))

      جاوا

      techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
  2. فراخوانی‌های برگشتی چرخه حیات فعالیت زیر را لغو کنید و منطقی را برای فعال و غیرفعال کردن ارسال پیش‌زمینه هنگام ازدست رفتن (onPause()) و به‌دست آوردن مجدد (onResume()) تمرکز فعالیت اضافه کنید. ‫enableForegroundDispatch() باید از رشته اصلی و فقط زمانی فراخوانی شود که فعالیت در پیش‌زمینه باشد (فراخوانی در onResume() این را تضمین می‌کند). همچنین باید فراخوانی برگشتی onNewIntent را برای پردازش داده‌های برچسب NFC اسکن‌شده پیاده‌سازی کنید.
  3. کاتلین

    public override fun onPause() {
        super.onPause()
        adapter.disableForegroundDispatch(this)
    }
    
    public override fun onResume() {
        super.onResume()
        adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray)
    }
    
    public override fun onNewIntent(intent: Intent) {
        val tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
        // do something with tagFromIntent
    }

    جاوا

    public void onPause() {
        super.onPause();
        adapter.disableForegroundDispatch(this);
    }
    
    public void onResume() {
        super.onResume();
        adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
    }
    
    public void onNewIntent(Intent intent) {
        Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        // do something with tagFromIntent
    }