مبانی NFC

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

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

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

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

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

  1. تجزیه برچسب NFC و تشخیص نوع MIME یا URI که بار داده موجود در برچسب را مشخص می‌کند.
  2. کپسوله‌سازی نوع MIME یا URI و payload در یک intent. این دو مرحله اول در بخش «نحوه نگاشت تگ‌های NFC به انواع MIME و URIها» توضیح داده شده است.
  3. یک فعالیت را بر اساس هدف (intent) آغاز می‌کند. این موضوع در بخش «نحوه ارسال برچسب‌های NFC به برنامه‌ها» توضیح داده شده است.

چگونه برچسب‌های NFC به انواع MIME و URIها نگاشت می‌شوند؟

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

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

توجه: برای دانلود مشخصات کامل NDEF، به سایت NFC Forum Specifications & Application Documents مراجعه کنید و برای مثال‌هایی از نحوه ساخت سوابق NDEF، به بخش ایجاد انواع رایج سوابق NDEF مراجعه کنید.

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

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

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

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

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

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

قالب نام نوع (TNF) نقشه برداری
TNF_ABSOLUTE_URI URI بر اساس فیلد نوع.
TNF_EMPTY به ACTION_TECH_DISCOVERED برمی‌گردد.
TNF_EXTERNAL_TYPE URI بر اساس URN در فیلد نوع. URN به صورت خلاصه در فیلد نوع NDEF کدگذاری می‌شود: <domain_name>:<service_name> . اندروید این را به یک 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 های موجود و نگاشت‌های آنها به جدول 2 مراجعه کنید.

جدول 2. 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 به برنامه‌ها

وقتی سیستم ارسال تگ، ایجاد یک intent که تگ NFC و اطلاعات شناسایی آن را در بر می‌گیرد، به پایان رسید، intent را به یک برنامه‌ی علاقه‌مند ارسال می‌کند که intent را فیلتر می‌کند. اگر بیش از یک برنامه بتواند intent را مدیریت کند، Activity Chooser نمایش داده می‌شود تا کاربر بتواند Activity را انتخاب کند. سیستم ارسال تگ، سه intent را تعریف می‌کند که به ترتیب اولویت از بالاترین به پایین‌ترین فهرست شده‌اند:

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

    توجه: از اندروید ۱۶ به بعد، اسکن تگ‌های NFC که لینک‌های URL را ذخیره می‌کنند (یعنی طرح URI آنها "htttps://" یا "http://" است)، به جای ACTION_NDEF_DISCOVERED هدف ACTION_VIEW فعال می‌کند.

  2. ACTION_TECH_DISCOVERED : اگر هیچ فعالیتی برای مدیریت هدف ACTION_NDEF_DISCOVERED ثبت نشده باشد، سیستم ارسال برچسب سعی می‌کند برنامه‌ای را با این هدف آغاز کند. این هدف همچنین مستقیماً (بدون شروع ACTION_NDEF_DISCOVERED در ابتدا) آغاز می‌شود اگر برچسبی که اسکن می‌شود حاوی داده‌های NDEF باشد که نمی‌توان آن را به یک نوع MIME یا URI نگاشت کرد، یا اگر برچسب حاوی داده‌های NDEF نباشد اما از یک فناوری برچسب شناخته شده باشد.
  3. ACTION_TAG_DISCOVERED : این intent در صورتی آغاز می‌شود که هیچ activity ی intent های ACTION_NDEF_DISCOVERED یا ACTION_TECH_DISCOVERED را مدیریت نکند.

روش کار اساسی سیستم ارسال برچسب به شرح زیر است:

  1. سعی کنید یک Activity را با هدفی که توسط سیستم ارسال تگ هنگام تجزیه تگ NFC ایجاد شده است ( ACTION_NDEF_DISCOVERED یا ACTION_TECH_DISCOVERED ) شروع کنید.
  2. اگر هیچ فعالیتی برای آن هدف فیلتر نشده باشد، سعی کنید یک فعالیت را با هدف بعدی با کمترین اولویت ( ACTION_TECH_DISCOVERED یا ACTION_TAG_DISCOVERED ) شروع کنید تا زمانی که یک برنامه برای این هدف فیلتر شود یا تا زمانی که سیستم ارسال برچسب تمام اهداف ممکن را امتحان کند.
  3. اگر هیچ برنامه‌ای هیچ یک از این اهداف را فیلتر نمی‌کند، هیچ کاری انجام ندهید.
شکل ۱. سیستم ارسال برچسب

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

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

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

  • عنصر <uses-permission> NFC برای دسترسی به سخت‌افزار NFC:
    <uses-permission android:name="android.permission.NFC" />
  • حداقل نسخه SDK که برنامه شما می‌تواند پشتیبانی کند. API سطح ۹ فقط از ارسال محدود تگ از طریق ACTION_TAG_DISCOVERED پشتیبانی می‌کند و فقط از طریق EXTRA_NDEF_MESSAGES extra به پیام‌های NDEF دسترسی می‌دهد. هیچ ویژگی تگ یا عملیات ورودی/خروجی دیگری قابل دسترسی نیست. API سطح ۱۰ شامل پشتیبانی جامع از خواننده/نویسنده و همچنین ارسال NDEF در پیش‌زمینه است و API سطح ۱۴ روش‌های راحت‌تری برای ایجاد رکوردهای NDEF ارائه می‌دهد.
    <uses-sdk android:minSdkVersion="10"/>
  • از عنصر uses-feature تا برنامه شما فقط برای دستگاه‌هایی که سخت‌افزار NFC دارند در گوگل پلی نمایش داده شود:
    <uses-feature android:name="android.hardware.nfc" android:required="true" />

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

فیلتر برای اهداف NFC

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

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

کشف_عملکرد_NDEF

برای فیلتر کردن intent های ACTION_NDEF_DISCOVERED ، فیلتر intent را به همراه نوع داده ای که می خواهید فیلتر کنید، تعریف کنید. مثال زیر intent های 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>

مثال زیر یک 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 فیلتر می‌شود، باید یک فایل منبع 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>
...
<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 از فیلتر intent زیر استفاده کنید:

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

نمای اکشن

از اندروید ۱۶ به بعد، اسکن تگ‌های NFC که لینک‌های URL را ذخیره می‌کنند، باعث فعال شدن ACTION_VIEW intent می‌شود. برای فیلتر کردن ACTION_VIEW به this مراجعه کنید. Android app links برای باز کردن برنامه خود برای URL استفاده کنید.

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

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

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

برای دریافت این موارد اضافی، بررسی کنید که آیا activity شما با یکی از اینتنت‌های 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 از intent دریافت کنید که شامل payload خواهد بود و به شما امکان می‌دهد فناوری‌های tag را بشمارید:

کاتلین

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

جاوا

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

ایجاد انواع رایج رکوردهای NDEF

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

این بخش همچنین نحوه ایجاد فیلتر intent مربوطه برای رکورد را شرح می‌دهد. همه این مثال‌های رکورد NDEF باید در اولین رکورد NDEF از پیام NDEF که در حال نوشتن آن در یک تگ هستید، باشند.

TNF_ABSOLUTE_URI

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

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

کاتلین

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]);

فیلتر intent برای رکورد 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() :

کاتلین

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

فیلتر intent برای رکورد 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 را به روش زیر ایجاد کنید:

کاتلین

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

فیلتر intent برای رکورد 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) :

کاتلین

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

فیلتر intent برای رکورد 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

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

استفاده از متد 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);

فیلتر intent برای رکورد 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>

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

توجه : URN های مربوط به TNF_EXTERNAL_TYPE دارای قالب استاندارد urn:nfc:ext:example.com:externalType هستند، با این حال، مشخصات RTD انجمن NFC اعلام می‌کند که بخش urn:nfc:ext: از URN باید از رکورد NDEF حذف شود. بنابراین تنها چیزی که باید ارائه دهید دامنه ( example.com در مثال) و نوع ( externalType در مثال) است که با یک دونقطه از هم جدا شده‌اند. هنگام ارسال TNF_EXTERNAL_TYPE ، اندروید URN urn:nfc:ext:example.com:externalType به یک URI vnd.android.nfc://ext/example.com:externalType تبدیل می‌کند، که همان چیزی است که فیلتر intent در مثال اعلام می‌کند.

سوابق برنامه‌های اندروید

رکورد برنامه اندروید (AAR) که در اندروید ۴.۰ (سطح API ۱۴) معرفی شد، اطمینان بیشتری از شروع برنامه شما هنگام اسکن یک تگ NFC فراهم می‌کند. یک AAR نام بسته یک برنامه را در داخل یک رکورد NDEF جاسازی شده دارد. می‌توانید یک AAR را به هر رکورد NDEF از پیام NDEF خود اضافه کنید، زیرا اندروید کل پیام NDEF را برای AARها جستجو می‌کند. اگر AAR را پیدا کند، برنامه را بر اساس نام بسته داخل AAR اجرا می‌کند. اگر برنامه در دستگاه وجود نداشته باشد، Google Play برای دانلود برنامه اجرا می‌شود.

AARها در صورتی مفید هستند که بخواهید از فیلتر کردن سایر برنامه‌ها برای همان intent و مدیریت تگ‌های خاصی که شما پیاده‌سازی کرده‌اید، جلوگیری کنید. AARها به دلیل محدودیت نام بسته، فقط در سطح برنامه پشتیبانی می‌شوند و مانند فیلتر کردن intent در سطح Activity پشتیبانی نمی‌شوند. اگر می‌خواهید intent را در سطح Activity مدیریت کنید، از فیلترهای intent استفاده کنید .

اگر یک تگ حاوی AAR باشد، سیستم ارسال تگ به روش زیر ارسال می‌کند:

  1. سعی کنید یک Activity را با استفاده از یک فیلتر intent به صورت عادی شروع کنید. اگر Activity که با intent مطابقت دارد با AAR نیز مطابقت دارد، Activity را شروع کنید.
  2. اگر Activity که intent را فیلتر می‌کند با AAR مطابقت نداشته باشد، اگر چندین Activity بتوانند intent را مدیریت کنند، یا اگر هیچ Activity ای intent را مدیریت نمی‌کند، برنامه‌ای که توسط AAR مشخص شده است را اجرا کنید.
  3. اگر هیچ برنامه‌ای نمی‌تواند با AAR اجرا شود، به گوگل پلی بروید تا برنامه‌ای را که بر اساس AAR است دانلود کنید.

نکته: شما می‌توانید AARها و سیستم اعزام intent را با سیستم اعزام پیش‌زمینه (foreground dispatch system) لغو کنید، که به یک activity پیش‌زمینه اجازه می‌دهد هنگام کشف یک تگ NFC اولویت داشته باشد. با این روش، activity باید در پیش‌زمینه باشد تا AARها و سیستم اعزام intent را لغو کند.

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

اندروید یک API ساده برای ایجاد یک AAR createApplicationRecord() ارائه می‌دهد. تنها کاری که باید انجام دهید این است که AAR را در هر جایی از NdefMessage خود جاسازی کنید. شما نمی‌خواهید از اولین رکورد NdefMessage خود استفاده کنید، مگر اینکه AAR تنها رکورد در NdefMessage باشد. دلیل این امر این است که سیستم اندروید اولین رکورد 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

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

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

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

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