اصول اولیه NFC

این سند وظایف اصلی NFC را که در Android انجام می‌دهید شرح می‌دهد. این سند نحوه ارسال و دریافت داده‌های NFC را در قالب پیام‌های NDEF توضیح می‌دهد و میاناهای برنامه‌سازی کاربردی چارچوب Android را که از این ویژگی‌ها پشتیبانی می‌کنند شرح می‌دهد. برای موضوعات پیشرفته‌تر، ازجمله بحث درباره کار با داده‌های غیر NDEF، به NFC پیشرفته مراجعه کنید.

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

سیستم ارسال برچسب

دستگاه‌های مجهز به Android معمولاً وقتی صفحه‌نمایش قفل نیست، به‌دنبال برچسب‌های NFC می‌گردند، مگراینکه 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 در طیف گسترده‌ای از فناوری‌ها ارائه می‌شوند و همچنین می‌توان داده‌ها را به روش‌های مختلفی در آن‌ها نوشت. Android بیشترین پشتیبانی را از استاندارد NDEF دارد که توسط NFC Forum تعریف شده است.

داده‌های NDEF در داخل پیامی (NdefMessage) که حاوی یک یا چند سابقه (NdefRecord) است کپسوله‌سازی می‌شود. هر سابقه NDEF باید طبق مشخصات نوع سابقه‌ای که می‌خواهید ایجاد کنید، خوش‌ساخت باشد. Android از انواع دیگر برچسب‌هایی که حاوی داده‌های NDEF نیستند نیز پشتیبانی می‌کند، که می‌توانید بااستفاده از کلاس‌های موجود در بسته android.nfc.tech با آن‌ها کار کنید. برای کسب اطلاعات بیشتر درباره این فناوری‌ها، به موضوع NFC پیشرفته مراجعه کنید. کار با این انواع دیگر برچسب‌ها شامل نوشتن پشته پروتکل خودتان برای برقراری ارتباط با برچسب‌ها است، بنابراین توصیه می‌کنیم برای سهولت توسعه و حداکثر پشتیبانی از دستگاه‌های مجهز به Android، درصورت امکان از NDEF استفاده کنید.

توجه: برای بارگیری مشخصات کامل NDEF، به سایت NFC Forum Specifications & Application Documents بروید و Creating common types of NDEF records را برای نمونه‌هایی از نحوه ساختن سوابق NDEF ببینید.

اکنون که اطلاعاتی درباره برچسب‌های NFC دارید، بخش‌های زیر با جزئیات بیشتری توضیح می‌دهند که Android چگونه برچسب‌های با قالب NDEF را مدیریت می‌کند. وقتی دستگاهی با سیستم‌عامل Android برچسب NFC حاوی داده‌های قالب‌بندی‌شده NDEF را اسکن می‌کند، پیام را تجزیه می‌کند و سعی می‌کند نوع MIME یا URI شناسایی داده‌ها را تشخیص دهد. برای انجام این کار، سیستم اولین NdefRecord را در NdefMessage می‌خواند تا نحوه تفسیر کل پیام NDEF را تعیین کند (یک پیام NDEF می‌تواند چندین سابقه NDEF داشته باشد). در پیام NDEF با قالب‌بندی صحیح، اولین NdefRecord شامل فیلدهای زیر است:

TNF‏ ۳ بیتی (قالب نام نوع)
نشان می‌دهد که چگونه فیلد نوع طول متغیر را تفسیر کنید. مقادیر معتبر در جدول ۱ شرح داده شده است.
نوع طول متغیر
نوع سابقه را شرح می‌دهد. اگر از TNF_WELL_KNOWN استفاده می‌کنید، از این فیلد برای مشخص کردن «تعریف نوع ضبط» (RTD) استفاده کنید. مقادیر معتبر RTD در جدول ۲ شرح داده شده است.
شناسه با طول متغیر
شناسه یکتای سابقه. این فیلد اغلب استفاده نمی‌شود، اما اگر لازم است برچسبی را به‌طور منحصربه‌فرد شناسایی کنید، می‌توانید شناسه‌ای برای آن ایجاد کنید.
پایه‌بار با طول متغیر
بار داده واقعی که می‌خواهید بخوانید یا بنویسید. یک پیام NDEF می‌تواند حاوی چندین رکورد NDEF باشد، بنابراین فرض نکنید که بار کامل در اولین رکورد NDEF پیام NDEF قرار دارد.

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

جدول ۱ نحوه نگاشت TNF و فیلدهای نوع به نوع MIME یا URI توسط سیستم ارسال برچسب را شرح می‌دهد. همچنین توضیح می‌دهد که کدام TNFها را نمی‌توان به نوع MIME یا URI نگاشت کرد. در این موارد، سیستم ارسال برچسب به ACTION_TECH_DISCOVERED برمی‌گردد.

برای مثال، اگر سیستم ارسال برچسب با رکوردی از نوع TNF_ABSOLUTE_URI مواجه شود، فیلد نوع طول متغیر آن رکورد را به یک URI نگاشت می‌کند. سیستم ارسال برچسب، آن URI را در فیلد داده یک هدف ACTION_NDEF_DISCOVERED به‌همراه اطلاعات دیگر درباره برچسب، مانند بار مفید، کپسوله‌سازی می‌کند. ازسوی‌دیگر، اگر با رکوردی از نوع TNF_UNKNOWN مواجه شود، قصدی ایجاد می‌کند که فناوری‌های برچسب را دربرمی‌گیرد.

جدول ۱. TNFهای پشتیبانی‌شده و نگاشت‌های آن‌ها

قالب نام نوع (TNF) تخصیص
TNF_ABSOLUTE_URI URI براساس فیلد نوع.
TNF_EMPTY به ACTION_TECH_DISCOVERED برمی‌گردد.
TNF_EXTERNAL_TYPE URI براساس URN در فیلد نوع. ‫URN در فیلد نوع NDEF به‌صورت خلاصه کدگذاری می‌شود: <domain_name>:<service_name>. Android این را به یک URI در فرم زیر نگاشت می‌کند: 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 نوع MIME یا URI بسته به «تعریف نوع ضبط» (RTD) که در فیلد نوع تنظیم می‌کنید. برای اطلاعات بیشتر درباره RTDهای دردسترس و نگاشت‌های آن‌ها، به جدول ۲ مراجعه کنید.

جدول ۲. RTDهای پشتیبانی‌شده برای TNF_WELL_KNOWN و نگاشت‌های آن‌ها

تعریف نوع گزارش (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 نوع MIME text/plain.
RTD_URI URI براساس بار داده.

نحوه ارسال برچسب‌های NFC به برنامه‌ها

وقتی سیستم ارسال برچسب ایجاد قصدی را که برچسب NFC و اطلاعات شناسایی آن را دربرمی‌گیرد به‌پایان رساند، قصد را به برنامه علاقه‌مندی که قصد را فیلتر می‌کند ارسال می‌کند. اگر بیش‌از یک برنامه بتواند هدف را مدیریت کند، «انتخابگر فعالیت» ارائه می‌شود تا کاربر بتواند «فعالیت» را انتخاب کند. سیستم ارسال برچسب سه قصد را تعریف می‌کند، که به‌ترتیب از بالاترین به پایین‌ترین اولویت فهرست شده‌اند:

  1. ACTION_NDEF_DISCOVERED: این هدف برای شروع یک «فعالیت» استفاده می‌شود، زمانی که برچسبی حاوی بار مفید NDEF اسکن می‌شود و از نوع شناخته‌شده‌ای است. این بالاترین اولویت هدف است و سیستم ارسال برچسب تلاش می‌کند تا هر زمان که ممکن باشد، یک فعالیت را با این هدف قبل از هر هدف دیگری شروع کند.

    توجه: از Android 16، اسکن کردن برچسب‌های NFC که پیوندهای وب را ذخیره می‌کنند (یعنی طرح‌واره URI آن‌ها «http://‎» یا «https://‎» است) به‌جای قصد ACTION_NDEF_DISCOVERED، قصد ACTION_VIEW را راه‌اندازی می‌کند. از Android 17، اسکن کردن چنین برچسبی اعلان «باز کردن پیوند» را نمایش می‌دهد که برای راه‌اندازی هدف ACTION_VIEW به تعامل صریح کاربر نیاز دارد.

  2. ACTION_TECH_DISCOVERED: اگر هیچ فعالیتی برای رسیدگی به هدف ACTION_NDEF_DISCOVERED ثبت نشده باشد، سیستم ارسال برچسب سعی می‌کند برنامه‌ای را با این هدف شروع کند. اگر برچسب اسکن‌شده حاوی داده‌های NDEF باشد که نمی‌توانند به نوع MIME یا URI نگاشت شوند، یا اگر برچسب حاوی داده‌های 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. اگر هیچ برنامه‌ای برای هیچ‌کدام از هدف‌ها فیلتر نشود، کاری انجام نمی‌شود.
شکل ۱. Tag Dispatch System

هرزمان ممکن بود، با پیام‌های NDEF و قصد ACTION_NDEF_DISCOVERED کار کنید، زیرا این قصد از بین سه قصد موجود، خاص‌ترین است. این هدف به شما امکان می‌دهد برنامه‌تان را در زمان مناسب‌تری نسبت‌به دو هدف دیگر شروع کنید و تجربه بهتری به کاربر ارائه دهید.

درخواست دسترسی NFC در مانیفست Android

قبل‌از اینکه بتوانید به سخت‌افزار NFC دستگاه دسترسی پیدا کنید و هدف‌های NFC را به‌درستی مدیریت کنید، این موارد را در فایل AndroidManifest.xml خود اعلام کنید:

  • عنصر NFC <uses-permission> برای دسترسی به سخت‌افزار NFC:
    <uses-permission android:name="android.permission.NFC" />
  • از Android 17 (سطح میانای برنامه‌سازی کاربردی ۳۷)، برای اینکه یک فعالیت هدف NFC را ارسال کند، اگر برنامه SDK > Build.VERSION_CODES.BAKLAVA را هدف قرار دهد، باید با اجازه android.permission.DISPATCH_NFC_MESSAGE محافظت شود. این کار تضمین می‌کند که فقط سرویس سیستم NFC بتواند هدف‌ها را به فعالیت شما ارسال کند. علاوه‌براین، سیستم هدف‌های NFC را به برنامه‌هایی که در وضعیت متوقف‌شده هستند ارسال نخواهد کرد (برای مثال اگر برنامه هرگز توسط کاربر راه‌اندازی نشده باشد یا به‌اجبار متوقف شده باشد).
    <activity
        android:name=".MyActivity"
        android:exported="true"
        android:permission="android.permission.DISPATCH_NFC_MESSAGE">
        ...
    </activity>
  • حداقل نسخه کیت توسعه نرم‌افزار که برنامه شما می‌تواند پشتیبانی کند. سطح ای‌پی‌آی ۹ فقط از ارسال برچسب محدود ازطریق ACTION_TAG_DISCOVERED پشتیبانی می‌کند و فقط ازطریق EXTRA_NDEF_MESSAGES اضافی به پیام‌های NDEF دسترسی می‌دهد. هیچ ویژگی برچسب یا عملیات ورودی/خروجی دیگری قابل‌دسترسی نیست. سطح ای‌پی‌آی ۱۰ شامل پشتیبانی جامع خواننده/نویسنده و همچنین ارسال NDEF پیش‌زمینه است، و سطح ای‌پی‌آی ۱۴ روش‌های راحت‌تری برای ایجاد سوابق NDEF ارائه می‌دهد.
    <uses-sdk android:minSdkVersion="10"/>
  • عنصر uses-feature تا برنامه‌تان در Google Play فقط برای دستگاه‌هایی که سخت‌افزار NFC دارند نشان داده شود:
    <uses-feature android:name="android.hardware.nfc" android:required="true" />

    اگر برنامه‌تان از عملکرد NFC استفاده می‌کند، اما این عملکرد برای برنامه‌تان حیاتی نیست، می‌توانید عنصر uses-feature را حذف کنید و با بررسی اینکه آیا getDefaultAdapter() برابر با null است یا نه، دردسترس بودن NFC را در زمان اجرا بررسی کنید.

فیلتر کردن برای هدف‌های NFC

برای شروع برنامه‌تان هنگام اسکن شدن برچسب NFC که می‌خواهید مدیریت کنید، برنامه‌تان می‌تواند برای یک، دو، یا هر سه هدف NFC در مانیفست Android فیلتر کند. بااین‌حال، معمولاً می‌خواهید برای قصد ACTION_NDEF_DISCOVERED فیلتر کنید تا بیشترین کنترل را بر زمان شروع برنامه‌تان داشته باشید. هدف ACTION_TECH_DISCOVERED جایگزینی برای ACTION_NDEF_DISCOVERED است وقتی هیچ برنامه‌ای برای ACTION_NDEF_DISCOVERED فیلتر نمی‌کند یا وقتی بار مفید NDEF نیست. فیلتر کردن برای ACTION_TAG_DISCOVERED معمولاً دسته‌ای بسیار کلی برای فیلتر کردن است. بسیاری از برنامه‌ها قبل‌از ACTION_TAG_DISCOVERED، برای ACTION_NDEF_DISCOVERED یا ACTION_TECH_DISCOVERED فیلتر می‌کنند، بنابراین احتمال شروع برنامه شما کم است. ACTION_TAG_DISCOVERED فقط به‌عنوان آخرین راهکار برای برنامه‌ها دردسترس است تا در مواردی که هیچ برنامه دیگری برای رسیدگی به هدف ACTION_NDEF_DISCOVERED یا ACTION_TECH_DISCOVERED نصب نشده است، فیلتر کنند.

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

ACTION_NDEF_DISCOVERED

برای فیلتر کردن برای هدف‌های ACTION_NDEF_DISCOVERED، فیلتر هدف را به‌همراه نوع داده‌ای که می‌خواهید برای آن فیلتر کنید اعلام کنید. مثال زیر برای مقصدهای ACTION_NDEF_DISCOVERED با نوع MIME‏ text/plain فیلتر می‌کند:

<activity
    android:name=".MyActivity"
    android:exported="true"
    android:permission="android.permission.DISPATCH_NFC_MESSAGE">
    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

مثال زیر برای URI به‌شکل https://developer.android.com/index.html فیلتر می‌کند.

<activity
    android:name=".MyActivity"
    android:exported="true"
    android:permission="android.permission.DISPATCH_NFC_MESSAGE">
    <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>
</activity>

ACTION_TECH_DISCOVERED

اگر فعالیت شما برای هدف ACTION_TECH_DISCOVERED فیلتر می‌کند، باید فایل منبع XML ایجاد کنید که فناوری‌هایی را که فعالیت شما پشتیبانی می‌کند در مجموعه tech-list مشخص کند. اگر مجموعه tech-list زیرمجموعه‌ای از فناوری‌هایی باشد که برچسب پشتیبانی می‌کند، فعالیت شما مطابقت درنظر گرفته می‌شود. می‌توانید این مجموعه را با فراخوانی getTechList() دریافت کنید.

برای مثال، اگر برچسب اسکن‌شده از MifareClassic،‏ NdefFormatable، و NfcA پشتیبانی می‌کند، مجموعه 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 به‌طور مستقل درنظر گرفته می‌شود و اگر هرکدام از مجموعه‌های 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>
    <tech-list>
        <tech>android.nfc.tech.NfcB</tech>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
</resources>

در فایل AndroidManifest.xml، فایل منبعی را که به‌تازگی ایجاد کرده‌اید در عنصر <meta-data> داخل عنصر <activity> مشخص کنید، مانند مثال زیر:

<activity
    android:name=".MyActivity"
    android:exported="true"
    android:permission="android.permission.DISPATCH_NFC_MESSAGE">
    <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 از Android 17 (سطح ای‌پی‌آی ۳۷) منسوخ شده است. درعوض از ACTION_NDEF_DISCOVERED یا ACTION_TECH_DISCOVERED استفاده کنید.

برای فیلتر کردن ACTION_TAG_DISCOVERED، از فیلتر قصد زیر استفاده کنید:

<activity
    android:name=".MyActivity"
    android:exported="true"
    android:permission="android.permission.DISPATCH_NFC_MESSAGE">
    <intent-filter>
        <action android:name="android.nfc.action.TAG_DISCOVERED"/>
    </intent-filter>
</activity>

ACTION_VIEW

از Android 16، اسکن کردن برچسب‌های NFC که پیوندهای وب را ذخیره می‌کنند (یعنی طرح‌واره URI آن‌ها «http://‎» یا «https://‎» است) به‌جای قصد ACTION_NDEF_DISCOVERED، قصد ACTION_VIEW را راه‌اندازی می‌کند. از Android 17، اسکن کردن چنین برچسبی باعث نمایش اعلان «باز کردن پیوند» می‌شود که برای راه‌اندازی هدف ACTION_VIEW به تعامل صریح کاربر نیاز دارد. برای فیلتر کردن ACTION_VIEW، به this مراجعه کنید. از Android app links برای باز کردن برنامه برای نشانی وب استفاده کنید.

دریافت اطلاعات از هدف‌ها

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

  • EXTRA_TAG (الزامی): شیء Tag که برچسب اسکن‌شده را نشان می‌دهد.
  • EXTRA_NDEF_MESSAGES (اختیاری): آرایه‌ای از پیام‌های NDEF تجزیه‌شده از برچسب. این مورد اضافی در ACTION_NDEF_DISCOVERED قصد اجباری است.
  • EXTRA_ID (اختیاری): شناسه سطح پایین برچسب.

برای دریافت این موارد اضافی، بررسی کنید که آیا فعالیت شما با یکی از هدف‌های NFC راه‌اندازی شده است تا مطمئن شوید برچسبی اسکن شده است، و سپس موارد اضافی را از هدف دریافت کنید. مثال زیر ACTION_NDEF_DISCOVERED را بررسی می‌کند و پیام‌های NDEF را از قصد اضافی دریافت می‌کند.

کاتلین

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 را از هدف دریافت کنید که حاوی بار مفید خواهد بود و به شما امکان می‌دهد فناوری‌های برچسب را فهرست کنید:

کاتلین

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

جاوا

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

ایجاد انواع متداول سوابق NDEF

این بخش نحوه ایجاد انواع رایج سوابق NDEF را شرح می‌دهد تا هنگام نوشتن در برچسب‌های NFC به شما کمک کند. از Android 4.0 (سطح API‏ ۱۴) به بعد، روش createUri() برای کمک به شما در ایجاد خودکار سوابق URI دردسترس است. از Android 4.1 (سطح میانای برنامه‌سازی کاربردی ۱۶) به بعد، createExternal() و createMime() برای کمک به شما در ایجاد سوابق NDEF نوع خارجی و MIME دردسترس هستند. هرزمان ممکن بود از این روش‌های کمکی استفاده کنید تا هنگام ایجاد دستی سوابق NDEF اشتباهی رخ ندهد.

این بخش همچنین نحوه ایجاد فیلتر قصد متناظر برای رکورد را شرح می‌دهد. همه این نمونه‌های سابقه NDEF باید در اولین سابقه NDEF پیام NDEF که در برچسب می‌نویسید باشد.

TNF_ABSOLUTE_URI

توجه: توصیه می‌کنیم به‌جای TNF_ABSOLUTE_URI از نوع RTD_URI استفاده کنید، زیرا کارآمدتر است.

می‌توانید به روش زیر یک رکورد NDEF TNF_ABSOLUTE_URI ایجاد کنید :

کاتلین

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 قبلی به‌این‌صورت خواهد بود:

<activity
    android:name=".MyActivity"
    android:exported="true"
    android:permission="android.permission.DISPATCH_NFC_MESSAGE">
    <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>
</activity>

TNF_MIME_MEDIA

می‌توانید به روش‌های زیر یک رکورد TNF_MIME_MEDIA NDEF ایجاد کنید:

استفاده از روش createMime():

کاتلین

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 به‌صورت دستی:

کاتلین

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 قبلی به‌این‌صورت خواهد بود:

<activity
    android:name=".MyActivity"
    android:exported="true"
    android:permission="android.permission.DISPATCH_NFC_MESSAGE">
    <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>
</activity>

TNF_WELL_KNOWN با RTD_TEXT

می‌توانید به روش زیر یک رکورد NDEF TNF_WELL_KNOWN ایجاد کنید:

کاتلین

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 قبلی به‌این‌صورت خواهد بود:

<activity
    android:name=".MyActivity"
    android:exported="true"
    android:permission="android.permission.DISPATCH_NFC_MESSAGE">
    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

TNF_WELL_KNOWN با RTD_URI

می‌توانید به روش‌های زیر یک رکورد TNF_WELL_KNOWN NDEF ایجاد کنید:

استفاده از روش createUri(String):

کاتلین

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

جاوا

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

استفاده از روش createUri(Uri):

کاتلین

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

جاوا

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

ایجاد کردن NdefRecord به‌صورت دستی:

کاتلین

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)

جاوا

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 قبلی به‌این‌صورت خواهد بود:

<activity
    android:name=".MyActivity"
    android:exported="true"
    android:permission="android.permission.DISPATCH_NFC_MESSAGE">
    <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>
</activity>

TNF_EXTERNAL_TYPE

می‌توانید به روش‌های زیر یک رکورد NDEF TNF_EXTERNAL_TYPE ایجاد کنید:

استفاده از روش createExternal():

کاتلین

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 به‌صورت دستی:

کاتلین

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 قبلی به‌این‌صورت خواهد بود:

<activity
    android:name=".MyActivity"
    android:exported="true"
    android:permission="android.permission.DISPATCH_NFC_MESSAGE">
    <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>
</activity>

برای استقرار برچسب NFC عمومی‌تر از TNF_EXTERNAL_TYPE استفاده کنید تا از دستگاه‌های مجهز به Android و غیرمجهز به Android بهتر پشتیبانی شود.

توجه: URN برای TNF_EXTERNAL_TYPE دارای قالب متعارف زیر است: urn:nfc:ext:example.com:externalType، اما مشخصات NFC Forum RTD اعلام می‌کند که بخش urn:nfc:ext: از URN باید از سوابق 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» (AAR) که در Android نسخه ۴.۰ (سطح میانای برنامه‌سازی کاربردی ۱۴) معرفی شد، اطمینان بیشتری فراهم می‌کند که برنامه شما هنگام اسکن شدن برچسب NFC شروع می‌شود. AAR نام بسته برنامه‌ای را دارد که در سابقه NDEF جاسازی شده است. می‌توانید به هر سابقه NDEF در پیام NDEF خود یک AAR اضافه کنید، زیرا Android کل پیام NDEF را برای یافتن AAR جستجو می‌کند. اگر AAR پیدا کند، برنامه را براساس نام بسته داخل AAR شروع می‌کند. اگر برنامه در دستگاه وجود نداشته باشد، Google Play برای بارگیری برنامه راه‌اندازی می‌شود.

اگر می‌خواهید از فیلتر کردن برنامه‌های دیگر برای همان قصد و احتمالاً مدیریت برچسب‌های خاصی که مستقر کرده‌اید جلوگیری کنید، «قوانین اِعمال خودکار» مفید هستند. AAR فقط در سطح برنامه پشتیبانی می‌شود، زیرا محدودیت نام بسته وجود دارد، و نه در سطح «فعالیت» مانند فیلتر کردن هدف. اگر می‌خواهید قصدی را در سطح «فعالیت» مدیریت کنید، از فیلترهای قصد استفاده کنید.

اگر برچسبی حاوی «توصیه‌های اِعمال خودکار» باشد، سیستم ارسال برچسب به روش زیر ارسال می‌کند:

  1. سعی کنید «فعالیتی» را بااستفاده از فیلتر قصد به‌طور معمول شروع کنید. اگر «فعالیت» منطبق با هدف با AAR نیز مطابقت دارد، «فعالیت» را شروع کنید.
  2. اگر «فعالیتی» که برای هدف فیلتر می‌کند با AAR مطابقت نداشته باشد، اگر چندین «فعالیت» بتوانند هدف را مدیریت کنند، یا اگر هیچ «فعالیتی» هدف را مدیریت نکند، برنامه مشخص‌شده توسط AAR را شروع کنید.
  3. اگر هیچ برنامه‌ای نتواند با AAR شروع شود، به Google Play بروید تا برنامه را براساس AAR بارگیری کنید.

توجه: می‌توانید توصیه‌های اِعمال خودکار و سیستم ارسال هدف را با سیستم ارسال پیش‌زمینه لغو کنید، که به فعالیت پیش‌زمینه اجازه می‌دهد هنگام کشف شدن برچسب NFC اولویت داشته باشد. با این روش، فعالیت باید در پیش‌زمینه باشد تا AAR و سیستم ارسال هدف را لغو کند.

اگر همچنان می‌خواهید برچسب‌های اسکن‌شده‌ای را که حاوی AAR نیستند فیلتر کنید، می‌توانید فیلترهای قصد را به‌صورت عادی اعلام کنید. این کار زمانی مفید است که برنامه شما به برچسب‌های دیگری که حاوی AAR نیستند علاقه داشته باشد. برای مثال، شاید بخواهید تضمین کنید که برنامه‌تان برچسب‌های اختصاصی‌ای را که شما مستقر می‌کنید و همچنین برچسب‌های عمومی‌ای را که اشخاص ثالث مستقر می‌کنند مدیریت می‌کند. به‌خاطر داشته باشید که AAR مختص دستگاه‌های Android 4.0 یا جدیدتر است، بنابراین هنگام استقرار برچسب‌ها، احتمالاً می‌خواهید از ترکیبی از AAR و انواع MIME/‏URI برای پشتیبانی از گسترده‌ترین طیف دستگاه‌ها استفاده کنید. علاوه‌براین، هنگام استقرار برچسب‌های NFC، به این فکر کنید که چگونه می‌خواهید برچسب‌های NFC خود را بنویسید تا پشتیبانی از اکثر دستگاه‌ها (دستگاه‌های مجهز به Android و سایر دستگاه‌ها) را فعال کنید. می‌توانید این کار را با تعریف کردن نوع MIME یا URI نسبتاً منحصربه‌فرد انجام دهید تا تشخیص آن برای برنامه‌ها آسان‌تر شود.

‫Android یک میانای برنامه‌سازی کاربردی ساده برای ایجاد «توصیه‌های اِعمال خودکار» ارائه می‌دهد، createApplicationRecord(). تنها کاری که باید انجام دهید این است که «توصیه‌های اِعمال خودکار» را در هر جایی از NdefMessage جاسازی کنید. نمی‌خواهید از اولین سابقه NdefMessage خود استفاده کنید، مگراینکه «توصیه‌های اِعمال خودکار» تنها سابقه در NdefMessage باشد. دلیل این امر این است که سیستم Android اولین رکورد NdefMessage را برای تعیین نوع MIME یا URI برچسب بررسی می‌کند، که برای ایجاد یک intent برای فیلتر کردن برنامه‌ها استفاده می‌شود. کد زیر نحوه ایجاد AAR را نشان می‌دهد:

کاتلین

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

جاوا

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

فهرست مجاز برنامه برای اسکن کردن نشان NFC

از Android 16، وقتی برنامه‌ای اولین هدف NFC خود را برای اسکن برچسب‌های NFC دریافت می‌کند، به کاربران اطلاع داده می‌شود. در اعلان، گزینه‌ای به کاربر ارائه می‌شود تا به برنامه اجازه ندهد دیگر برچسب‌های NFC را اسکن کند.

  • برنامه‌ها می‌توانند بااستفاده از NfcAdapter.isTagIntentAllowed() بررسی کنند که آیا کاربر به برنامه اجازه داده است برچسب‌های NFC را اسکن کند یا نه.
  • برنامه‌ها می‌توانند با ارسال هدف ACTION_CHANGE_TAG_INTENT_PREFERENCE، از کاربر بخواهند که دوباره اجازه اسکن برچسب NFC را بدهد.

توجه: فهرست مجاز برنامه اسکن برچسب NFC در Settings > Apps > Special app access > Launch via NFC قابل‌دسترسی است.

این سازوکار برای رفع نگرانی‌های مطرح‌شده ازسوی کاربران اضافه شده است، زیرا برخی‌از برنامه‌هایی که فیلترهای قصد را برای قصد برچسب NFC ثبت کرده بودند، وقتی تلفن را کنار برچسب NFC (کارت اعتباری، تلفن/ساعت دیگر، و غیره) قرار می‌دادند، مکرراً به پیش‌زمینه آورده می‌شدند.