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ề 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ạng thông báo NDEF, đồng thời mô tả các API khung Android hỗ trợ các tính năng này. Để biết thêm 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 đã 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. Ứng dụng muốn xử lý thẻ NFC đã quét có thể khai báo bộ lọc ý định và yêu cầu xử lý dữ liệu.

Hệ thống điều phối 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 bạn tắt NFC 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ẻ NFC, hành vi mong muốn là để hoạt động phù hợp nhất 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 việc yêu cầu người dùng chọn một hoạt động theo cách thủ công có thể buộc họ phải di chuyển thiết bị ra khỏi thẻ và ngắt kết nối. Bạn nên phát triển hoạt động của mình để chỉ xử lý các thẻ NFC mà hoạt động của bạn quan tâ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 điều phố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. Cách thực hiện như sau:

  1. Phân tích cú pháp thẻ NFC và tìm hiểu 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 liên kết thẻ NFC với 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 thẻ NFC được gửi đến ứng dụng.

Cách liên kết thẻ NFC với loại MIME và URI

Trước khi bắt đầu viết ứ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ô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 NFC Forum 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 định dạng đúng theo thông số kỹ thuật 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 mà bạn có thể xử lý 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. Khi làm việc với các loại thẻ khác, bạn cần phải viết ngăn xếp giao thức của riêng mình để giao tiếp với các 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 xuống thông số kỹ thuật NDEF đầy đủ, hãy truy cập vào trang web Tài liệu ứng dụng và thông số kỹ thuật của NFC Forum và 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, 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ý 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 của dữ liệu hoặc xác định URI. Để thực hiện 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 một thông báo NDEF được định dạng đúng cách, NdefRecord đầu tiên chứa các trường sau:

TNF 3 bit (Định dạng tên loại)
Cho biết cách diễn giải trường loại độ dài biến. Các giá trị hợp lệ được mô tả trong Bảng 1.
Loại có độ dài biến
Mô tả loại bản ghi. Nếu sử dụng TNF_WELL_KNOWN, hãy sử 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ã có độ dài biến
Giá trị nhận dạng duy nhất của bản ghi. Trường này không được sử dụng thường xuyên, nhưng nếu cần xác định riêng một thẻ, bạn có thể tạo mã nhận dạng cho thẻ đó.
Trọng tải có độ dài biến
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 giả định 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 liên kết một loại MIME hoặc URI với thông báo NDEF. Nếu thành công, phương thức này sẽ đóng gói thông tin đó bên trong một ý định ACTION_NDEF_DISCOVERED cùng với tải trọng thực tế. Tuy nhiên, có trường hợp hệ thống điều phối thẻ không thể xác định loại dữ liệu dựa trên bản ghi NDEF đầu tiên. Điều này xảy ra khi không thể liên kết dữ liệu NDEF với 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, đố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 ý định ACTION_TECH_DISCOVERED.

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

Ví dụ: nếu hệ thống điều phối thẻ gặp một bản ghi thuộc loại TNF_ABSOLUTE_URI, thì hệ thống sẽ liên kết trường loại độ dài biến của bản ghi đó vào một URI. Hệ thống điều phối thẻ đóng gói URI đó trong trường dữ liệu của ý đị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ì trình phân tích cú pháp sẽ tạo một ý định đóng gói các công nghệ của thẻ.

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

Định dạng tên loại (TNF) Ánh xạ
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 liên kết thông tin này với một URI ở 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, vì vậy, hãy 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 đặt 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 các RTD đó.

Bảng 2. Các RTD được hỗ trợ cho TNF_WELL_KNOWN và các ánh xạ của chúng

Định nghĩa loại bản ghi (RTD) Ánh xạ
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 tải trọng.
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 gồm 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 để lọc ý định. Nếu có nhiều ứng dụng có thể xử lý ý định, 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 điều phối thẻ xác định ba ý định, được liệt kê theo thứ tự ư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 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 mọi ý định khác, bất cứ khi nào có thể.

    Lưu ý: Kể từ Android 16, việc quét thẻ NFC lưu trữ các đường liên kết URL (tức là lược đồ URI là "htttps://" 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ể liên kết với loại 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.

Cách hoạt động cơ bản của hệ thống điều phối thẻ như sau:

  1. Hãy thử 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ó hoạt động nào lọc ý định đó, hãy thử khởi động một Hoạt động có ý định ư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ả ý định có thể.
  3. Nếu không có ứng dụng nào lọc cho bất kỳ ý định nào, bạn không cần làm gì cả.
Hình 1. Hệ thống điều phối thẻ

Bất cứ khi nào có thể, hãy làm việc với thông báo NDEF và ý định ACTION_NDEF_DISCOVERED, vì đây là thông báo cụ thể nhất trong số ba thông báo. Ý đị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 hai ý định còn lại, mang lại cho người dùng trải nghiệm tốt hơn.

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 các mục này trong tệp AndroidManifest.xml:

  • Phần tử <uses-permission> NFC để 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ỉ cấp quyền truy cập vào thông báo NDEF thông qua EXTRA_NDEF_MESSAGES bổ sung. Không truy cập được các thuộc tính thẻ hoặc thao tác I/O nào khác. API cấp 10 bao gồm tính năng hỗ trợ đầu đọc/bộ ghi toàn diện cũng như tính năng đẩy NDEF trên nền trước, còn API cấp 14 cung cấp các phương thức thuận tiện khác để 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 các 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 ý đị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 để kiểm soát tối đa thời điểm ứng dụng khởi động. Ý định ACTION_TECH_DISCOVERED là phương án dự phòng cho ACTION_NDEF_DISCOVERED khi không có ứng dụng nào lọc cho ACTION_NDEF_DISCOVERED hoặc khi tải trọng không phải là NDEF. Việc lọc cho ACTION_TAG_DISCOVERED thường quá chung chung đối với một danh mục để 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ó ít khả năng khởi động. ACTION_TAG_DISCOVERED chỉ được cung cấp như một phương án cuối cùng cho 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 khi không nằm trong 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ể làm được việc này. Đó là lý do bạn có thể sử dụng hai ý định còn lại khi cần. 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 ý đị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. Ví dụ sau đây về bộ lọc 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 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 ý định ACTION_TECH_DISCOVERED, bạn phải tạo một tệp tài nguyên XML chỉ định các 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à 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ả ba, hai hoặc một trong các công nghệ (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 bất kỳ) trong 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 tập hợp 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 xem là 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ệ do 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 so khớp các 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 làm việc với 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 ACTION_VIEW, hãy tham khảo this. Sử dụng Android app links để mở ứng dụng cho URL.

Thu thập 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 thông tin 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ẻ đã quét.
  • EXTRA_NDEF_MESSAGES (không bắt buộc): Một mảng 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 ý đị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 thông tin 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 thẻ đã được quét, sau đó lấy các thông tin bổ sung từ ý đị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 đố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 để giúp bạn khi ghi vào thẻ NFC. Kể từ Android 4.0 (API cấp 14), phương thức createUri() sẽ giúp bạn tự động tạo bản ghi URI. Kể từ Android 4.1 (API cấp 16), bạn có thể sử dụng createExternal()createMime() để tạo bản ghi MIME và NDEF loại bên ngoài. 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 sai sót 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 các 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 với 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 với RTD_URI

Bạn có thể tạo bản ghi NDEF TNF_WELL_KNOWN theo các 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 các 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 để triển khai thẻ NFC chung hơn nhằm hỗ trợ tốt hơn cả thiết bị chạy Android và 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, thông số kỹ thuật RTD của NFC Forum khai báo rằng phần urn:nfc:ext: của URN phải được bỏ qua 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 điều phố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à nội dung mà bộ lọc ý định trong ví dụ khai báo.

Bản ghi ứng dụng Android

Được ra mắt trong Android 4.0 (API cấp 14), Bản ghi ứng dụng Android (AAR) giúp tăng độ chắc chắn rằng ứng dụng của bạn sẽ khởi động khi quét thẻ NFC. 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 AAR vào bất kỳ bản ghi NDEF nào của thông báo NDEF, vì Android sẽ tìm kiếm AAR trong toàn bộ thông báo NDEF. Nếu tìm thấy AAR, thì ứng dụng sẽ bắt đầu 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ẽ được khởi chạy để tải ứng dụng xuống.

AAR hữu ích nếu bạn muốn ngăn các ứng dụng khác lọc theo cùng một ý định và có thể xử lý các thẻ cụ thể mà bạn đã triển khai. AAR chỉ được hỗ trợ ở cấp ứng dụng do quy tắc ràng buộc tên gói, chứ không phải ở cấp Hoạt động như với tính năng 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. Hãy 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ể bắt đầu bằng AAR, hãy truy cập vào Google Play để tải ứng dụng dựa trên AAR xuống.

Lưu ý: Bạn có thể ghi đè AAR và hệ thống điều phối ý định bằng hệ thống điều phối trên nền trước. Hệ thống này cho phép hoạt động trên nền trước có mức độ ưu tiên khi phát hiện 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 điều phối ý định.

Nếu vẫn muốn lọc các thẻ đã 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. Ngoài ra, khi triển khai thẻ NFC, hãy cân nhắc 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 để các ứng dụng dễ dàng phân biệt hơn.

Android cung cấp một API đơn giản để tạo tệp AAR, createApplicationRecord(). Tất cả những gì bạn cần làm là nhúng AAR vào bất kỳ vị trí nào trong NdefMessage. Bạn không nê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 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 ý định cho các ứng dụng lọc. Mã sau đây cho bạn 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ẽ được thông báo khi một ứng dụng nhận được ý định NFC đầu tiên để quét thẻ NFC. Trong thông báo, người dùng có thể chọn không cho phép ứng dụng quét thẻ NFC nữa.

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

Cơ chế này được thêm vào để giải quyết các mối lo ngại mà người dùng đưa ra khi một số ứng dụng đã đăng ký bộ lọc ý định cho ý định thẻ NFC liên tục được đưa vào 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.).