نظرة عامة على تقنية NFC المتقدمة

يوضِّح هذا المستند مواضيع متقدّمة عن تقنية NFC، مثل استخدام تكنولوجيات مختلفة للعلامات، والكتابة إلى علامات NFC، والإرسال في المقدّمة، ما يسمح للتطبيق الذي يعمل في المقدّمة بمعالجة الأهداف حتى عندما تستخدم التطبيقات الأخرى الفلاتر نفسها.

العمل باستخدام تقنيات العلامات المتوافقة

عند التعامل مع علامات NFC والأجهزة التي تعمل بنظام التشغيل Android، يكون التنسيق الرئيسي الذي تستخدمه لقراءة البيانات وكتابتها على العلامات هو NDEF. عندما يفحص جهاز علامة تتضمّن بيانات NDEF، يوفِّر نظام التشغيل Android الدعم في تحليل الرسالة وتسليمها في NdefMessage إن أمكن. ومع ذلك، هناك حالات تفحص فيها علامة لا تحتوي على بيانات NDEF أو يتعذّر فيها ربط بيانات NDEF إلى نوع MIME أو معرّف موارد منتظم (URI). في هذه الحالات، تحتاج إلى فتح الاتصال مباشرةً بالعلامة وقراءتها والكتابة فيها باستخدام البروتوكول الخاص بك (بوحدات بايت غير معدَّلة). يوفِّر نظام التشغيل Android دعمًا عامًا لحالات الاستخدام هذه من خلال حزمة android.nfc.tech الموضَّحة في الجدول 1. يمكنك استخدام طريقة getTechList() لتحديد التكنولوجيات المتوافقة مع العلامة وإنشاء كائن TagTechnology المقابل باستخدام إحدى الفئات التي توفّرها العلامة android.nfc.tech.

الجدول 1. تقنيات العلامات المتوافقة

الفئة الوصف
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.

الجدول 2. التكنولوجيات الاختيارية للعلامات المتوافقة

الفئة الوصف
MifareClassic يوفّر إمكانية الوصول إلى خصائص MIFARE الكلاسيكية وعمليات وحدات الإدخال والإخراج، إذا كان جهاز Android هذا متوافقًا مع MIFARE.
MifareUltralight يوفّر إمكانية الوصول إلى خصائص MIFARE Ultralight وعمليات وحدات الإدخال والإخراج، إذا كان جهاز Android هذا متوافقًا مع معيار MIFARE.

العمل باستخدام تقنيات العلامات والإجراء ACTION_TECH_DISCOVERED

عندما يفحص جهاز علامة تتضمّن بيانات NDEF، ولكن يتعذّر ربطها ببروتوكول MIME أو معرّف الموارد المنتظم (URI)، يحاول نظام إرسال العلامة بدء نشاط بقصد ACTION_TECH_DISCOVERED. تُستخدم ACTION_TECH_DISCOVERED أيضًا عند فحص علامة تحتوي على بيانات غير NDEF. يتيح لك إجراء هذا الإجراء الاحتياطي العمل على البيانات في العلامة مباشرةً إذا لم يتمكّن نظام إرسال العلامة من تحليلها نيابةً عنك. في ما يلي الخطوات الأساسية عند استخدام تقنيات العلامات:

  1. طبِّق الفلتر بحثًا عن هدف ACTION_TECH_DISCOVERED يحدّد تقنيات العلامات التي تريد معالجتها. راجع التصفية بحثًا عن نية استخدام NFC لمزيد من المعلومات. بشكل عام، يحاول نظام إرسال العلامات بدء هدف ACTION_TECH_DISCOVERED عندما يتعذّر ربط رسالة NDEF بنوع MIME أو معرّف موارد منتظم (URI)، أو إذا لم تكن العلامة التي تم فحصها تحتوي على بيانات NDEF. ولمزيد من المعلومات عن كيفية تحديد ذلك، راجِع نظام إرسال العلامات.
  2. عندما يتلقّى تطبيقك عنصر intent، احصل على الكائن Tag من سمة intent:

    Kotlin

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

    Java

    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    
  3. احصل على نسخة افتراضية من TagTechnology من خلال استدعاء إحدى أساليب get المصنعة للفئات في حزمة android.nfc.tech. يمكنك تعداد التكنولوجيات المتوافقة للعلامة عن طريق استدعاء getTechList() قبل طلب get بطريقة المصنع. على سبيل المثال، للحصول على مثيل MifareUltralight من Tag، يُرجى اتّباع الخطوات التالية:

    Kotlin

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

    Java

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

قراءة العلامات والكتابة فيها

وتتضمن القراءة والكتابة في علامة NFC الحصول على العلامة من قصدها وفتح الاتصال بها. عليك تحديد حزمة البروتوكول الخاصة بك لقراءة البيانات وكتابتها في العلامة. مع ذلك، ضع في اعتبارك أنه لا يزال بإمكانك قراءة بيانات NDEF وكتابتها عند العمل مباشرةً باستخدام العلامة. الأمر متروك لك في كيفية هيكلة الأشياء. يوضح المثال التالي كيفية التعامل مع علامة MIFARE Ultralight.

Kotlin

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

Java

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

استخدام نظام الإرسال في المقدّمة

يسمح نظام الإرسال الذي يعمل في المقدّمة لنشاط باعتراض هدف وادّعاء الأولوية على الأنشطة الأخرى التي تعالج الهدف نفسه. ويتضمّن استخدام هذا النظام إنشاء بعض بُنى البيانات لنظام Android كي يتمكّن من إرسال الأغراض المناسبة إلى تطبيقك. لتفعيل نظام الإرسال في المقدّمة:

  1. أضِف الرمز التالي في طريقة onCreate() لنشاطك:
    1. أنشِئ عنصر PendingIntent قابلاً للتغيير حتى يتمكّن نظام Android من تعبئته بتفاصيل العلامة عند فحصها.

      Kotlin

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

      Java

      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. يجب معالجة الطلبات التي تحتاج إليها فقط.

      Kotlin

      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)
      

      Java

      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() للحصول على فئة التكنولوجيا التي تريد استخدامها.

      Kotlin

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

      Java

      techListsArray = new String[][] { new String[] { NfcF.class.getName() } };
      
  2. يمكنك إلغاء استدعاءات مراحل نشاط النشاط التالية وإضافة منطق لتفعيل إرسال البيانات في المقدّمة أو إيقافه عند فقدان النشاط (onPause()) واستعادة التركيز (onResume()). يجب استدعاء enableForegroundDispatch() من سلسلة التعليمات الرئيسية، وعندما يكون النشاط في المقدّمة فقط (يضمن استدعاء الدالة onResume() ذلك). عليك أيضًا تنفيذ استدعاء onNewIntent لمعالجة البيانات من علامة NFC الممسوحة ضوئيًا.
  3. Kotlin

    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
    }
    

    Java

    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
    }