Thông tin cơ bản về NFC

Tài liệu này mô tả các thao tác cơ bản với NFC mà bạn thực hiện trong Android. Tài liệu này giải thích cách gửi và nhận dữ liệu NFC dưới dạng thông báo NDEF, đồng thời mô tả các API khung Android hỗ trợ những tính năng này. Để biết thêm về các chủ đề nâng cao, bao gồm cả nội dung thảo luận về cách làm việc với dữ liệu không phải NDEF, hãy xem phần NFC nâng cao.

Việc đọc dữ liệu NDEF từ thẻ NFC được xử lý bằng hệ thống điều phối thẻ. Hệ thống này phân tích các thẻ NFC được phát hiện, phân loại dữ liệu một cách thích hợp và khởi động một ứng dụng quan tâm đến dữ liệu được phân loại. Một ứng dụng muốn xử lý thẻ NFC được quét có thể khai báo một bộ lọc ý định và yêu cầu xử lý dữ liệu.

Hệ thống truyền thẻ

Các thiết bị chạy Android thường tìm thẻ NFC khi màn hình được mở khoá, trừ phi NFC bị tắt trong trình đơn Cài đặt của thiết bị. Khi một thiết bị chạy Android phát hiện thấy thẻ NFC, hành vi mong muốn là hoạt động phù hợp nhất sẽ xử lý ý định mà không cần hỏi người dùng nên sử dụng ứng dụng nào. Vì các thiết bị quét thẻ NFC ở phạm vi rất ngắn, nên có khả năng việc yêu cầu người dùng chọn hoạt động theo cách thủ công sẽ buộc họ di chuyển thiết bị ra khỏi thẻ và làm gián đoạn kết nối. Bạn chỉ nên phát triển hoạt động của mình để xử lý các thẻ NFC mà hoạt động đó quan tâm nhằm ngăn Trình chọn hoạt động xuất hiện.

Để giúp bạn đạt được mục tiêu này, Android cung cấp một hệ thống gửi thẻ đặc biệt để phân tích các thẻ NFC đã quét, phân tích cú pháp các thẻ đó và cố gắng xác định vị trí các ứng dụng quan tâm đến dữ liệu đã quét. Thao tác này được thực hiện bằng cách:

  1. Phân tích cú pháp thẻ NFC và tìm ra loại MIME hoặc URI xác định tải trọng dữ liệu trong thẻ.
  2. Đóng gói loại MIME hoặc URI và tải trọng vào một ý định. Hai bước đầu tiên này được mô tả trong phần Cách ánh xạ thẻ NFC với các loại MIME và URI.
  3. Bắt đầu một hoạt động dựa trên ý định. Điều này được mô tả trong phần Cách gửi thẻ NFC đến các ứng dụng.

Cách ánh xạ thẻ NFC với các loại MIME và URI

Trước khi bắt đầu viết các ứng dụng NFC, bạn cần hiểu rõ các loại thẻ NFC, cách hệ thống điều phối thẻ phân tích cú pháp thẻ NFC và công việc đặc biệt mà hệ thống điều phối thẻ thực hiện khi phát hiện thấy một thông báo NDEF. Thẻ NFC có nhiều công nghệ và cũng có thể ghi dữ liệu vào thẻ theo nhiều cách. Android hỗ trợ nhiều nhất cho tiêu chuẩn NDEF do Diễn đàn NFC xác định.

Dữ liệu NDEF được đóng gói bên trong một thông báo (NdefMessage) chứa một hoặc nhiều bản ghi (NdefRecord). Mỗi bản ghi NDEF phải có cấu trúc phù hợp theo quy cách của loại bản ghi mà bạn muốn tạo. Android cũng hỗ trợ các loại thẻ khác không chứa dữ liệu NDEF. Bạn có thể làm việc với các loại thẻ này bằng cách sử dụng các lớp trong gói android.nfc.tech. Để tìm hiểu thêm về các công nghệ này, hãy xem chủ đề NFC nâng cao. Việc sử dụng các loại thẻ khác này liên quan đến việc viết ngăn xếp giao thức của riêng bạn để giao tiếp với thẻ. Vì vậy, bạn nên sử dụng NDEF khi có thể để dễ dàng phát triển và hỗ trợ tối đa cho các thiết bị chạy Android.

Lưu ý: Để tải thông số kỹ thuật NDEF đầy đủ xuống, hãy truy cập vào trang web NFC Forum Specifications & Application Documents (Thông số kỹ thuật và tài liệu ứng dụng của Diễn đàn NFC) rồi xem phần Tạo các loại bản ghi NDEF phổ biến để biết ví dụ về cách tạo bản ghi NDEF.

Giờ đây, khi bạn đã có một số kiến thức cơ bản về thẻ NFC, các phần sau đây sẽ mô tả chi tiết hơn về cách Android xử lý các thẻ được định dạng NDEF. Khi một thiết bị chạy Android quét thẻ NFC chứa dữ liệu được định dạng NDEF, thiết bị sẽ phân tích cú pháp thông báo và cố gắng tìm ra loại MIME hoặc URI nhận dạng của dữ liệu. Để làm việc này, hệ thống sẽ đọc NdefRecord đầu tiên bên trong NdefMessage để xác định cách diễn giải toàn bộ thông báo NDEF (một thông báo NDEF có thể có nhiều bản ghi NDEF). Trong thông báo NDEF có cấu trúc hợp lệ, NdefRecord đầu tiên chứa các trường sau:

TNF (Định dạng tên loại) 3 bit
Cho biết cách diễn giải trường loại có độ dài thay đổi. Các giá trị hợp lệ được mô tả trong Bảng 1.
Loại có độ dài thay đổi
Mô tả loại bản ghi. Nếu sử dụng TNF_WELL_KNOWN, hãy dùng trường này để chỉ định Định nghĩa loại bản ghi (RTD). Các giá trị RTD hợp lệ được mô tả trong Bảng 2.
Mã nhận dạng có độ dài thay đổi
Giá trị nhận dạng riêng biệt của bản ghi. Trường này không được dùng thường xuyên, nhưng nếu cần xác định duy nhất một thẻ, bạn có thể tạo mã nhận dạng cho thẻ đó.
Tải trọng có độ dài thay đổi
Tải trọng dữ liệu thực tế mà bạn muốn đọc hoặc ghi. Một thông báo NDEF có thể chứa nhiều bản ghi NDEF, vì vậy, đừng cho rằng toàn bộ tải trọng nằm trong bản ghi NDEF đầu tiên của thông báo NDEF.

Hệ thống điều phối thẻ sử dụng các trường TNF và loại để cố gắng ánh xạ một loại MIME hoặc URI đến thông báo NDEF. Nếu thành công, thông tin đó sẽ được đóng gói bên trong một ý định ACTION_NDEF_DISCOVERED cùng với tải trọng thực tế. Tuy nhiên, có những trường hợp hệ thống gửi thẻ không xác định được loại dữ liệu dựa trên bản ghi NDEF đầu tiên. Điều này xảy ra khi dữ liệu NDEF không thể được liên kết với một loại MIME hoặc URI, hoặc khi thẻ NFC không chứa dữ liệu NDEF ngay từ đầu. Trong những trường hợp như vậy, một đối tượng Tag có thông tin về các công nghệ của thẻ và tải trọng sẽ được đóng gói bên trong một ý định ACTION_TECH_DISCOVERED.

Bảng 1 mô tả cách hệ thống điều phối thẻ ánh xạ các trường TNF và loại sang các loại MIME hoặc URI. Nó cũng mô tả những TNF không thể được liên kết với một loại MIME hoặc URI. Trong những trường hợp này, hệ thống gửi thẻ sẽ quay lại ACTION_TECH_DISCOVERED.

Ví dụ: nếu hệ thống phân phối thẻ gặp một bản ghi thuộc loại TNF_ABSOLUTE_URI, hệ thống sẽ ánh xạ trường loại có độ dài thay đổi của bản ghi đó thành một URI. Hệ thống điều phối thẻ sẽ đóng gói URI đó trong trường dữ liệu của một ý định ACTION_NDEF_DISCOVERED cùng với các thông tin khác về thẻ, chẳng hạn như tải trọng. Mặt khác, nếu gặp một bản ghi thuộc loại TNF_UNKNOWN, thì hệ thống sẽ tạo một ý định bao bọc các công nghệ của thẻ thay vì tạo một bản ghi.

Bảng 1. Các TNF được hỗ trợ và mối liên kết của chúng

Định dạng tên loại (TNF) Liên kết
TNF_ABSOLUTE_URI URI dựa trên trường loại.
TNF_EMPTY Quay lại ACTION_TECH_DISCOVERED.
TNF_EXTERNAL_TYPE URI dựa trên URN trong trường loại. URN được mã hoá vào trường loại NDEF ở dạng rút gọn: <domain_name>:<service_name>. Android ánh xạ URI này thành một URI có dạng: vnd.android.nfc://ext/<domain_name>:<service_name>.
TNF_MIME_MEDIA Loại MIME dựa trên trường loại.
TNF_UNCHANGED Không hợp lệ trong bản ghi đầu tiên, nên sẽ quay lại ACTION_TECH_DISCOVERED.
TNF_UNKNOWN Quay lại ACTION_TECH_DISCOVERED.
TNF_WELL_KNOWN Loại MIME hoặc URI, tuỳ thuộc vào Định nghĩa loại bản ghi (RTD) mà bạn thiết lập trong trường loại. Hãy xem Bảng 2 để biết thêm thông tin về các RTD hiện có và mối liên kết của chúng.

Bảng 2. Các RTD được hỗ trợ cho TNF_WELL_KNOWN và các mối liên kết của chúng

Định nghĩa loại bản ghi (RTD) Liên kết
RTD_ALTERNATIVE_CARRIER Quay lại ACTION_TECH_DISCOVERED.
RTD_HANDOVER_CARRIER Quay lại ACTION_TECH_DISCOVERED.
RTD_HANDOVER_REQUEST Quay lại ACTION_TECH_DISCOVERED.
RTD_HANDOVER_SELECT Quay lại ACTION_TECH_DISCOVERED.
RTD_SMART_POSTER URI dựa trên việc phân tích cú pháp trọng tải.
RTD_TEXT Loại MIME của text/plain.
RTD_URI URI dựa trên tải trọng.

Cách thẻ NFC được gửi đến các ứng dụng

Khi hệ thống điều phối thẻ hoàn tất việc tạo một ý định bao bọc thẻ NFC và thông tin nhận dạng của thẻ, hệ thống sẽ gửi ý định đó đến một ứng dụng quan tâm có bộ lọc cho ý định. Nếu có nhiều ứng dụng có thể xử lý ý định này, thì Trình chọn hoạt động sẽ xuất hiện để người dùng có thể chọn Hoạt động. Hệ thống gửi thẻ xác định 3 ý định, được liệt kê theo thứ tự từ mức độ ưu tiên cao nhất đến thấp nhất:

  1. ACTION_NDEF_DISCOVERED: Ý định này dùng để bắt đầu một Hoạt động khi một thẻ chứa tải trọng NDEF được quét và thuộc một loại được nhận dạng. Đây là ý định có mức độ ưu tiên cao nhất và hệ thống điều phối thẻ sẽ cố gắng khởi động một Hoạt động bằng ý định này trước bất kỳ ý định nào khác, bất cứ khi nào có thể.

    Lưu ý: Kể từ Android 16, việc quét các thẻ NFC lưu trữ đường liên kết URL (tức là lược đồ URI là "https://" hoặc "http://") sẽ kích hoạt ý định ACTION_VIEW thay vì ý định ACTION_NDEF_DISCOVERED.

  2. ACTION_TECH_DISCOVERED: Nếu không có hoạt động nào đăng ký xử lý ý định ACTION_NDEF_DISCOVERED, thì hệ thống điều phối thẻ sẽ cố gắng khởi động một ứng dụng bằng ý định này. Ý định này cũng được bắt đầu trực tiếp (mà không cần bắt đầu ACTION_NDEF_DISCOVERED trước) nếu thẻ được quét chứa dữ liệu NDEF không thể được liên kết với một kiểu MIME hoặc URI, hoặc nếu thẻ không chứa dữ liệu NDEF nhưng thuộc một công nghệ thẻ đã biết.
  3. ACTION_TAG_DISCOVERED: Ý định này được bắt đầu nếu không có hoạt động nào xử lý ý định ACTION_NDEF_DISCOVERED hoặc ACTION_TECH_DISCOVERED.

Sau đây là cách hoạt động cơ bản của hệ thống điều phối thẻ:

  1. Cố gắng bắt đầu một Hoạt động bằng ý định do hệ thống điều phối thẻ tạo khi phân tích cú pháp thẻ NFC (ACTION_NDEF_DISCOVERED hoặc ACTION_TECH_DISCOVERED).
  2. Nếu không có bộ lọc hoạt động nào cho ý định đó, hãy thử bắt đầu một Hoạt động bằng ý định có mức độ ưu tiên thấp nhất tiếp theo (ACTION_TECH_DISCOVERED hoặc ACTION_TAG_DISCOVERED) cho đến khi một ứng dụng lọc ý định hoặc cho đến khi hệ thống điều phối thẻ thử tất cả các ý định có thể.
  3. Nếu không có ứng dụng nào lọc cho bất kỳ ý định nào, thì không làm gì cả.
Hình 1. Tag Dispatch System

Bất cứ khi nào có thể, hãy sử dụng thông báo NDEF và ý định ACTION_NDEF_DISCOVERED, vì đây là ý định cụ thể nhất trong số 3 ý định. Ý định này cho phép bạn khởi động ứng dụng vào thời điểm thích hợp hơn so với 2 ý định còn lại, mang lại trải nghiệm tốt hơn cho người dùng.

Yêu cầu quyền truy cập NFC trong tệp kê khai Android

Trước khi bạn có thể truy cập vào phần cứng NFC của thiết bị và xử lý đúng cách các ý định NFC, hãy khai báo những mục này trong tệp AndroidManifest.xml:

  • Phần tử NFC <uses-permission> để truy cập vào phần cứng NFC:
    <uses-permission android:name="android.permission.NFC" />
  • Phiên bản SDK tối thiểu mà ứng dụng của bạn có thể hỗ trợ. API cấp 9 chỉ hỗ trợ việc gửi thẻ có giới hạn thông qua ACTION_TAG_DISCOVERED và chỉ cho phép truy cập vào thông báo NDEF thông qua phần bổ sung EXTRA_NDEF_MESSAGES. Không thể truy cập vào các thuộc tính thẻ hoặc thao tác I/O khác. API cấp 10 có khả năng hỗ trợ toàn diện cho trình đọc/ghi cũng như tính năng đẩy NDEF ở nền trước, còn API cấp 14 cung cấp các phương thức tiện lợi bổ sung để tạo bản ghi NDEF.
    <uses-sdk android:minSdkVersion="10"/>
  • Phần tử uses-feature để ứng dụng của bạn chỉ xuất hiện trong Google Play đối với những thiết bị có phần cứng NFC:
    <uses-feature android:name="android.hardware.nfc" android:required="true" />

    Nếu ứng dụng của bạn sử dụng chức năng NFC nhưng chức năng đó không quan trọng đối với ứng dụng, bạn có thể bỏ qua phần tử uses-feature và kiểm tra xem có NFC hay không trong thời gian chạy bằng cách kiểm tra xem getDefaultAdapter() có phải là null hay không.

Lọc các ý định NFC

Để khởi động ứng dụng khi một thẻ NFC mà bạn muốn xử lý được quét, ứng dụng của bạn có thể lọc một, hai hoặc cả ba ý định NFC trong tệp kê khai Android. Tuy nhiên, bạn thường muốn lọc ý định ACTION_NDEF_DISCOVERED để có quyền kiểm soát cao nhất đối với thời điểm ứng dụng của bạn bắt đầu. Ý định ACTION_TECH_DISCOVERED là một phương án dự phòng cho ACTION_NDEF_DISCOVERED khi không có bộ lọc ứng dụng cho ACTION_NDEF_DISCOVERED hoặc khi tải trọng không phải là NDEF. Việc lọc theo ACTION_TAG_DISCOVERED thường là một danh mục quá chung chung để lọc. Nhiều ứng dụng sẽ lọc ACTION_NDEF_DISCOVERED hoặc ACTION_TECH_DISCOVERED trước ACTION_TAG_DISCOVERED, vì vậy, ứng dụng của bạn có khả năng khởi động thấp. ACTION_TAG_DISCOVERED chỉ có sẵn dưới dạng phương án cuối cùng để các ứng dụng lọc trong trường hợp không có ứng dụng nào khác được cài đặt để xử lý ý định ACTION_NDEF_DISCOVERED hoặc ACTION_TECH_DISCOVERED.

Vì việc triển khai thẻ NFC rất đa dạng và nhiều lần nằm ngoài tầm kiểm soát của bạn, nên không phải lúc nào bạn cũng có thể thực hiện được việc này. Đó là lý do bạn có thể quay lại hai ý định còn lại khi cần thiết. Khi có quyền kiểm soát các loại thẻ và dữ liệu được ghi, bạn nên sử dụng NDEF để định dạng thẻ. Các phần sau đây mô tả cách lọc cho từng loại ý định.

ACTION_NDEF_DISCOVERED

Để lọc các ý định ACTION_NDEF_DISCOVERED, hãy khai báo bộ lọc ý định cùng với loại dữ liệu mà bạn muốn lọc. Sau đây là các bộ lọc ví dụ cho ý định ACTION_NDEF_DISCOVERED có loại MIME là 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>

Ví dụ sau đây lọc theo một URI ở dạng 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

Nếu hoạt động của bạn lọc theo ý định ACTION_TECH_DISCOVERED, thì bạn phải tạo một tệp tài nguyên XML chỉ định những công nghệ mà hoạt động của bạn hỗ trợ trong một tập hợp tech-list. Hoạt động của bạn được coi là trùng khớp nếu một tập hợp tech-list là một tập hợp con của các công nghệ mà thẻ hỗ trợ. Bạn có thể lấy tập hợp này bằng cách gọi getTechList().

Ví dụ: nếu thẻ được quét hỗ trợ MifareClassic, NdefFormatable và NfcA, thì tập hợp tech-list của bạn phải chỉ định cả 3, 2 hoặc 1 trong số các công nghệ này (và không có công nghệ nào khác) để hoạt động của bạn được so khớp.

Mẫu sau đây xác định tất cả các công nghệ. Bạn phải xoá những thẻ không được thẻ NFC hỗ trợ. Lưu tệp này (bạn có thể đặt tên tuỳ ý) vào thư mục <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>

Bạn cũng có thể chỉ định nhiều bộ tech-list. Mỗi tập hợp tech-list được xem xét độc lập và hoạt động của bạn được coi là trùng khớp nếu bất kỳ tập hợp tech-list nào là một tập hợp con của các công nghệ mà getTechList() trả về. Điều này cung cấp ngữ nghĩa ANDOR cho các công nghệ so khớp. Ví dụ sau đây khớp với những thẻ có thể hỗ trợ công nghệ NfcA và Ndef hoặc có thể hỗ trợ công nghệ NfcB và 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>

Trong tệp AndroidManifest.xml, hãy chỉ định tệp tài nguyên mà bạn vừa tạo trong phần tử <meta-data> bên trong phần tử <activity> như trong ví dụ sau:

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

Để biết thêm thông tin về cách sử dụng các công nghệ thẻ và ý định ACTION_TECH_DISCOVERED, hãy xem phần Làm việc với các công nghệ thẻ được hỗ trợ trong tài liệu NFC nâng cao.

ACTION_TAG_DISCOVERED

Để lọc ACTION_TAG_DISCOVERED, hãy sử dụng bộ lọc ý định sau:

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

ACTION_VIEW

Kể từ Android 16, việc quét thẻ NFC lưu trữ đường liên kết URL sẽ kích hoạt ý định ACTION_VIEW. Để lọc theo ACTION_VIEW, hãy tham khảo this. Sử dụng Android app links để mở ứng dụng cho URL.

Lấy thông tin từ ý định

Nếu một hoạt động bắt đầu do ý định NFC, bạn có thể lấy thông tin về thẻ NFC đã quét từ ý định đó. Ý định có thể chứa các phần bổ sung sau đây, tuỳ thuộc vào thẻ đã được quét:

  • EXTRA_TAG (bắt buộc): Một đối tượng Tag đại diện cho thẻ được quét.
  • EXTRA_NDEF_MESSAGES (không bắt buộc): Một mảng gồm các thông báo NDEF được phân tích cú pháp từ thẻ. Thông tin bổ sung này là bắt buộc đối với các ý định ACTION_NDEF_DISCOVERED.
  • EXTRA_ID (không bắt buộc): Mã nhận dạng cấp thấp của thẻ.

Để lấy các phần bổ sung này, hãy kiểm tra xem hoạt động của bạn có được khởi chạy bằng một trong các ý định NFC hay không để đảm bảo rằng một thẻ đã được quét, sau đó lấy các phần bổ sung ra khỏi ý định. Ví dụ sau đây sẽ kiểm tra ý định ACTION_NDEF_DISCOVERED và nhận thông báo NDEF từ một ý định bổ sung.

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

Ngoài ra, bạn có thể lấy một đối tượng Tag từ ý định. Đối tượng này sẽ chứa tải trọng và cho phép bạn liệt kê các công nghệ của thẻ:

Kotlin

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

Java

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

Tạo các loại bản ghi NDEF phổ biến

Phần này mô tả cách tạo các loại bản ghi NDEF phổ biến để hỗ trợ bạn khi ghi vào thẻ NFC. Kể từ Android 4.0 (API cấp 14), phương thức createUri() có sẵn để giúp bạn tự động tạo các bản ghi URI. Kể từ Android 4.1 (API cấp 16), createExternal()createMime() có sẵn để giúp bạn tạo bản ghi NDEF loại bên ngoài và MIME. Hãy sử dụng các phương thức trợ giúp này bất cứ khi nào có thể để tránh mắc lỗi khi tạo bản ghi NDEF theo cách thủ công.

Phần này cũng mô tả cách tạo bộ lọc ý định tương ứng cho bản ghi. Tất cả các ví dụ về bản ghi NDEF này phải nằm trong bản ghi NDEF đầu tiên của thông báo NDEF mà bạn đang ghi vào thẻ.

TNF_ABSOLUTE_URI

Lưu ý: Bạn nên sử dụng loại RTD_URI thay vì TNF_ABSOLUTE_URI vì loại này hiệu quả hơn.

Bạn có thể tạo bản ghi NDEF TNF_ABSOLUTE_URI theo cách sau :

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

Bộ lọc ý định cho bản ghi NDEF trước đó sẽ có dạng như sau:

<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

Bạn có thể tạo bản ghi NDEF TNF_MIME_MEDIA theo những cách sau:

Sử dụng phương thức 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")));

Tạo NdefRecord theo cách thủ công:

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

Bộ lọc ý định cho bản ghi NDEF trước đó sẽ có dạng như sau:

<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 có RTD_TEXT

Bạn có thể tạo bản ghi NDEF TNF_WELL_KNOWN theo cách sau:

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

Bộ lọc ý định cho bản ghi NDEF trước đó sẽ có dạng như sau:

<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 có RTD_URI

Bạn có thể tạo bản ghi NDEF TNF_WELL_KNOWN theo những cách sau:

Sử dụng phương thức createUri(String):

Kotlin

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

Java

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

Sử dụng phương thức 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);

Tạo NdefRecord theo cách thủ công:

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

Bộ lọc ý định cho bản ghi NDEF trước đó sẽ có dạng như sau:

<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

Bạn có thể tạo bản ghi NDEF TNF_EXTERNAL_TYPE theo những cách sau:

Sử dụng phương thức 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);

Tạo NdefRecord theo cách thủ công:

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

Bộ lọc ý định cho bản ghi NDEF trước đó sẽ có dạng như sau:

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

Sử dụng TNF_EXTERNAL_TYPE cho các hoạt động triển khai thẻ NFC chung hơn để hỗ trợ tốt hơn cả thiết bị chạy Android và thiết bị không chạy Android.

Lưu ý: URN cho TNF_EXTERNAL_TYPE có định dạng chuẩn là: urn:nfc:ext:example.com:externalType, tuy nhiên, quy cách RTD của Diễn đàn NFC tuyên bố rằng phần urn:nfc:ext: của URN phải bị loại bỏ khỏi bản ghi NDEF. Vì vậy, bạn chỉ cần cung cấp miền (example.com trong ví dụ) và loại (externalType trong ví dụ) được phân tách bằng dấu hai chấm. Khi gửi TNF_EXTERNAL_TYPE, Android sẽ chuyển đổi URN urn:nfc:ext:example.com:externalType thành URI vnd.android.nfc://ext/example.com:externalType. Đây là những gì bộ lọc ý định trong ví dụ khai báo.

Bản ghi ứng dụng Android

Được giới thiệu trong Android 4.0 (API cấp 14), Bản ghi ứng dụng Android (AAR) mang lại sự chắc chắn hơn rằng ứng dụng của bạn sẽ được khởi động khi một thẻ NFC được quét. AAR có tên gói của một ứng dụng được nhúng bên trong bản ghi NDEF. Bạn có thể thêm một AAR vào bất kỳ bản ghi NDEF nào trong thông báo NDEF, vì Android sẽ tìm kiếm toàn bộ thông báo NDEF để tìm AAR. Nếu tìm thấy một AAR, thì ứng dụng sẽ khởi động dựa trên tên gói bên trong AAR. Nếu ứng dụng không có trên thiết bị, Google Play sẽ khởi chạy để tải ứng dụng xuống.

AAR rất hữu ích nếu bạn muốn ngăn các ứng dụng khác lọc cùng một ý định và có khả năng xử lý các thẻ cụ thể mà bạn đã triển khai. AAR chỉ được hỗ trợ ở cấp ứng dụng, do hạn chế về tên gói, chứ không được hỗ trợ ở cấp Hoạt động như khi lọc ý định. Nếu bạn muốn xử lý một ý định ở cấp Hoạt động, hãy sử dụng bộ lọc ý định.

Nếu một thẻ chứa AAR, hệ thống điều phối thẻ sẽ điều phối theo cách sau:

  1. Thử bắt đầu một Hoạt động bằng bộ lọc ý định như bình thường. Nếu Hoạt động khớp với ý định cũng khớp với AAR, hãy bắt đầu Hoạt động.
  2. Nếu Hoạt động lọc ý định không khớp với AAR, nếu nhiều Hoạt động có thể xử lý ý định hoặc nếu không có Hoạt động nào xử lý ý định, hãy khởi động ứng dụng do AAR chỉ định.
  3. Nếu không có ứng dụng nào có thể khởi động bằng AAR, hãy chuyển đến Google Play để tải ứng dụng xuống dựa trên AAR.

Lưu ý: Bạn có thể ghi đè AAR và hệ thống gửi ý định bằng hệ thống gửi ở nền trước. Hệ thống này cho phép một hoạt động ở nền trước có quyền ưu tiên khi phát hiện thấy thẻ NFC. Với phương thức này, hoạt động phải ở nền trước để ghi đè AAR và hệ thống gửi ý định.

Nếu vẫn muốn lọc các thẻ được quét không chứa AAR, bạn có thể khai báo bộ lọc ý định như bình thường. Điều này hữu ích nếu ứng dụng của bạn quan tâm đến các thẻ khác không chứa AAR. Ví dụ: có thể bạn muốn đảm bảo rằng ứng dụng của mình xử lý các thẻ độc quyền mà bạn triển khai cũng như các thẻ chung do bên thứ ba triển khai. Xin lưu ý rằng AAR dành riêng cho các thiết bị Android 4.0 trở lên, vì vậy, khi triển khai thẻ, bạn nên sử dụng kết hợp AAR và loại MIME/URI để hỗ trợ nhiều thiết bị nhất có thể. Ngoài ra, khi triển khai thẻ NFC, hãy nghĩ về cách bạn muốn ghi thẻ NFC để hỗ trợ hầu hết các thiết bị (thiết bị chạy Android và các thiết bị khác). Bạn có thể thực hiện việc này bằng cách xác định một loại MIME hoặc URI tương đối duy nhất để giúp các ứng dụng dễ dàng phân biệt.

Android cung cấp một API đơn giản để tạo AAR, createApplicationRecord(). Bạn chỉ cần nhúng AAR vào bất cứ đâu trong NdefMessage. Bạn không muốn sử dụng bản ghi đầu tiên của NdefMessage, trừ phi AAR là bản ghi duy nhất trong NdefMessage. Điều này là do hệ thống Android kiểm tra bản ghi đầu tiên của một NdefMessage để xác định loại MIME hoặc URI của thẻ. Loại MIME hoặc URI này được dùng để tạo một ý định cho các ứng dụng lọc. Đoạn mã sau đây cho biết cách tạo 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")}
        );
)

Danh sách cho phép ứng dụng để quét thẻ NFC

Kể từ Android 16, người dùng sẽ nhận được thông báo khi một ứng dụng nhận được ý định NFC đầu tiên để quét thẻ NFC. Người dùng có thể chọn không cho phép ứng dụng quét thẻ NFC nữa trong thông báo.

  • Các ứng dụng có thể kiểm tra xem người dùng đã cho phép ứng dụng quét thẻ NFC hay chưa bằng cách sử dụng NfcAdapter.isTagIntentAllowed().
  • Các ứng dụng có thể nhắc người dùng cho phép quét thẻ NFC một lần nữa bằng cách gửi ý định ACTION_CHANGE_TAG_INTENT_PREFERENCE.

Lưu ý: Bạn có thể truy cập vào danh sách cho phép ứng dụng quét thẻ NFC trong phần Settings > Apps > Special app access > Launch via NFC.

Cơ chế này được thêm vào để giải quyết những lo ngại của người dùng khi một số ứng dụng đã đăng ký bộ lọc ý định cho ý định thẻ NFC liên tục được đưa lên nền trước khi họ đặt điện thoại bên cạnh thẻ NFC (thẻ tín dụng, điện thoại/đồng hồ khác, v.v.).