高级 NFC 概览

2022/7/23 6:25:19

本文主要是介绍高级 NFC 概览,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

高级 NFC 概览

本文介绍了各种高级 NFC 主题,例如如何使用各种标签技术、如何写入 NFC 标签以及如何执行前台调度(借助前台调度,在前台运行的应用即使在其他应用过滤某些 Intent 时也能优先处理这些 Intent)。

使用支持的标签技术

将 NFC 标签与 Android 设备结合使用时,用于读取和写入标签数据的主要格式是 NDEF。当设备扫描具有 NDEF 数据的标签时,Android 会尽可能在解析消息和通过 NdefMessage 传递该消息方面提供支持。不过,在某些情况下,您扫描的标签可能不包含 NDEF 数据,或者 NDEF 数据无法映射为 MIME 类型或 URI。在这些情况下,您需要直接开启与标签的通信,并使用自己的协议(以原始字节形式)对标签执行读写操作。Android 通过 android.nfc.tech 软件包对这些用例提供一般性支持,如表 1 所述。您可以使用 getTechList() 方法确定标签支持的技术,还可以使用 android.nfc.tech 提供的一个类来创建相应的 TagTechnology 对象。

表 1. 支持的标签技术

说明
TagTechnology 这是所有标签技术类都必须实现的接口。
NfcA 提供对 NFC-A (ISO 14443-3A) 属性和 I/O 操作的访问权限。
NfcB 提供对 NFC-B (ISO 14443-3B) 属性和 I/O 操作的访问权限。
NfcF 提供对 NFC-F (JIS 6319-4) 属性和 I/O 操作的访问权限。
NfcV 提供对 NFC-V (ISO 15693) 属性和 I/O 操作的访问权限。
IsoDep 提供对 ISO-DEP (ISO 14443-4) 属性和 I/O 操作的访问权限。
Ndef 提供对 NDEF 格式的 NFC 标签上的 NDEF 数据和操作的访问权限。
NdefFormatable 为可设置为 NDEF 格式的标签提供格式化操作。

Android 设备还可以选择支持以下标签技术。

表 2. 可选择支持的标签技术

说明
MifareClassic 提供对 MIFARE Classic 属性和 I/O 操作的访问权限(如果此 Android 设备支持 MIFARE)。
MifareUltralight 提供对 MIFARE Ultralight 属性和 I/O 操作的访问权限(如果此 Android 设备支持 MIFARE)。

将标签技术和 ACTION_TECH_DISCOVERED Intent 结合使用

当设备扫描包含 NDEF 数据但无法映射为 MIME 或 URI 的标签时,标签调度系统会尝试使用 ACTION_TECH_DISCOVERED Intent 来启动 Activity。在扫描到包含非 NDEF 数据的标签时,也会使用 ACTION_TECH_DISCOVERED。如果标签调度系统无法解析标签数据,此回退功能可让您直接处理标签数据。使用标签技术的基本步骤如下:

  1. 过滤一个 ACTION_TECH_DISCOVERED Intent,指定您要处理的标签技术。如需了解详情,请参阅过滤 NFC Intent。通常,如果 NDEF 消息无法映射为 MIME 类型或 URI,或者扫描到的标签不包含 NDEF 数据,那么标签调度系统会尝试启动 ACTION_TECH_DISCOVERED Intent。如需详细了解具体的确定方式,请参阅标签调度系统。
  2. 应用收到 Intent 时,会从该 Intent 获取 Tag 对象: KotlinJava  
  •     var tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
        
  • 通过调用 android.nfc.tech 软件包中类的 get 工厂方法,获取 TagTechnology 的实例。您可以枚举支持的标签技术,只需在调用 get 工厂方法之前调用 getTechList() 即可。例如,要从 Tag 获取 MifareUltralight 的实例,请执行以下操作: KotlinJava  
  1.     MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG))
        

对标签执行读写操作

对 NFC 标签执行读写操作涉及从 Intent 获取标签以及开启与标签的通信。您必须定义自己的协议栈才能读写标签数据。不过,请注意,在直接处理标签时,您仍然可以读写 NDEF 数据,具体取决于您要如何设计其结构。下面的示例展示了如何使用 MIFARE Ultralight 标签。

KotlinJava  
    package com.example.android.nfc
    import android.nfc.Tag
    import android.nfc.tech.MifareUltralight
    import java.io.IOException
    import java.nio.charset.Charset

    class MifareUltralightTagTester {

        fun writeTag(tag: Tag, tagText: String) {
            MifareUltralight.get(tag)?.use { ultralight ->
                ultralight.connect()
                Charset.forName("US-ASCII").also { usAscii ->
                    ultralight.writePage(4, "abcd".toByteArray(usAscii))
                    ultralight.writePage(5, "efgh".toByteArray(usAscii))
                    ultralight.writePage(6, "ijkl".toByteArray(usAscii))
                    ultralight.writePage(7, "mnop".toByteArray(usAscii))
                }
            }

            fun readTag(tag: Tag): String? {
                return MifareUltralight.get(tag)?.use { mifare ->
                    mifare.connect()
                    val payload = mifare.readPages(4)
                    String(payload, Charset.forName("US-ASCII"))
                }
            }
        }
    }
    

使用前台调度系统

借助前台调度系统,Activity 可以拦截 Intent 并声明自己可优先于其他 Activity 处理同一 Intent。使用此系统涉及为 Android 系统构造一些数据结构,以便将合适的 Intent 发送到您的应用。要启用前台调度系统,请执行以下操作:

  1. 在 Activity 的 onCreate() 方法中添加以下代码:
    1. 创建一个 PendingIntent 对象,这样 Android 系统会使用扫描到的标签的详情对其进行填充。 KotlinJava  
  •     val intent = Intent(this, javaClass).apply {
            addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
        }
        var pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
        
  • 声明 Intent 过滤器,以处理您要拦截的 Intent。前台调度系统会对照设备扫描标签时所获得的 Intent 来检查所指定的 Intent 过滤器。如果匹配,那么应用会处理该 Intent。如果不匹配,那么前台调度系统会回退到 Intent 调度系统。指定 Intent 过滤器和技术过滤器的 null 数组,以指明要过滤所有回退到 TAG_DISCOVERED Intent 的标签。以下代码段会处理 NDEF_DISCOVERED 的所有 MIME 类型。您应只处理需要的内容。 KotlinJava  
  •     val ndef = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED).apply {
            try {
                addDataType("*/*")    /* Handles all MIME based dispatches.
                                         You should specify only the ones that you need. */
            } catch (e: IntentFilter.MalformedMimeTypeException) {
                throw RuntimeException("fail", e)
            }
        }
    
        intentFiltersArray = arrayOf(ndef)
        
  • 设置应用要处理的一组标签技术。调用 Object.class.getName() 方法以获取要支持的技术的类。 KotlinJava  
    1.     techListsArray = arrayOf(arrayOf<String>(NfcF::class.java.name))
          
  • 替换以下 Activity 生命周期回调,并添加相应逻辑,以分别在 Activity 失去 (onPause()) 焦点和重新获得 (onResume()) 焦点时启用和停用前台调度。enableForegroundDispatch() 必须从主线程调用,并且只能在 Activity 在前台运行时调用(在 onResume() 中调用可确保这一点)。您还需要实现 onNewIntent 回调以处理扫描到的 NFC 标签中的数据。
KotlinJava  
    public override fun onPause() {
        super.onPause()
        adapter.disableForegroundDispatch(this)
    }

    public override fun onResume() {
        super.onResume()
        adapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray)
    }

    public override fun onNewIntent(intent: Intent) {
        val tagFromIntent: Tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)
        //do something with tagFromIntent
    }
    

如需查看完整示例,请参阅 API 演示中的 ForegroundDispatch 示例。

Content and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Last updated 2019-12-27 UTC.



这篇关于高级 NFC 概览的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程