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ưới 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 bài viết NFC nâng cao.

Việc đọc dữ liệu NDEF từ thẻ NFC được xử lý thông qua 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 phù hợp và khởi động một ứng dụng quan tâm đến dữ liệu đã 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 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ẻ 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ì thiết bị quét thẻ NFC ở phạm vi rất ngắn, nên việc khiến người dùng chọn một hoạt động theo cách thủ công sẽ buộc họ phải di chuyển thiết bị ra xa 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ủa 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 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 bài viết 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 ứng dụng.

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

Trước khi bắt đầu viết ứng dụng NFC, bạn cần phải hiểu các loại thẻ NFC khác nhau, 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 tiêu chuẩn NDEF mà 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) có 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 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 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 toàn bộ thông số kỹ thuật NDEF xuống, hãy truy cập trang web Tài liệu ứng dụng và thông số kỹ thuật của diễn đàn NFC rồi xem bài viết Tạo các loại bản ghi NDEF phổ biến để tham khảo 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ẻ đó.
Tải trọng có chiều 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 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ó những trường hợp mà 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ẻ ánh xạ TNF và các trường kiểu với các 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 sử dụng 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ẻ sẽ đó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ì thao tác này 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) 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 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. Xem Bảng 2 để biết thêm thông tin về các RTD có sẵn 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 Trở về 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 hoàn tất việc tạo ý định đóng gói 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 quét một thẻ chứa tải trọng NDEF 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ể.
  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 với ý đị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ử 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ả ý định có thể.
  3. Nếu không có ứng dụng nào lọc ý định, thì 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 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 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 thể truy cập vào bất kỳ 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 dùng chức năng NFC nhưng chức năng đó không quan trọng đối với ứng dụng, thì bạn có thể bỏ qua phần tử uses-feature và kiểm tra khả năng sử dụng NFC 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, thông thường, bạn nên lọc ý định ACTION_NDEF_DISCOVERED để có nhiều quyền kiểm soát nhất đối với thời điểm khởi động ứng dụ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 dùng làm phương án cuối cùng cho các ứng dụng cần 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.

Do quy trình triển khai thẻ NFC khác nhau và nhiều lần không thuộc quyền kiểm soát của bạn, nên điều này không phải lúc nào cũng có thể xảy ra. Đó là lý do bạn có thể dự phòng cho 2 ý đị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 bạn muốn lọc. Sau đây là ví dụ về bộ lọc ý đị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>

Các bộ lọc mẫu sau đây cho 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 bất cứ tên nào bạn muốn) 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 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 coi 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ề. Việc 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>

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ẻ. Phần 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 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), bạn có thể sử dụng phương thức createUri() để 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 nhầm lẫn 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 Diễn đàn NFC khai báo rằng phần urn:nfc:ext: của URN phải được 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 đ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 giới thiệu 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 một 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 trên toàn bộ thông báo NDEF. Nếu tìm thấy một AAR, công cụ này sẽ khởi động ứng dụ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ẽ được 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 cho 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 chỉ 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 rất có thể muốn sử dụng kết hợp các loại/URI loại MIME và AAR để hỗ trợ nhiều loại thiết bị nhất có thể. Ngoài ra, khi bạn triển khai thẻ NFC, hãy nghĩ đến cách bạn muốn ghi thẻ NFC để cho phép hỗ trợ cho hầu hết các thiết bị (các 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 hướng dẫn bạn 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")}
        );
)