65.9K
CodeProject 正在变化。 阅读更多。
Home

使用案例研究进行 Android* 上的 NFC 应用开发

2014年7月22日

CPOL

7分钟阅读

viewsIcon

26709

本文介绍了当前市场中基于 NFC 的技术和使用模式。然后,它还描述了如何在 Android 应用程序中使用 NFC。最后,它提出了两个案例研究,说明如何开发基于 NFC 的读写器应用程序。

引言

NFC(近场通信)是一种基于标准的短距离无线连接技术,可实现电子设备之间简单直观的双向交互。在两个 NFC 设备之间进行接触和通信非常方便。例如,借助智能手机集成的 NFC 技术,您可以轻松地触碰手机进行购物、分享名片、下载折扣券等等。未来将开发出许多基于 NFC 的新用途。

本文介绍了当前市场中基于 NFC 的技术和使用模式。然后,它还描述了如何在 Android 应用程序中使用 NFC。最后,它提出了两个案例研究,说明如何开发基于 NFC 的读写器应用程序。

NFC 技术架构

NFC 基于 13.56 MHz 的 RFID 技术,典型工作距离可达 10 厘米。数据交换速率高达 424 千比特/秒。与其他通信技术相比,NFC 最大的优势在于其使用快速简便。下图比较了 NFC 与其他通信技术。

图 1:短距离通信技术比较

NFC 技术有三种模式:NFC 卡模拟模式、点对点模式和读写器模式,如下图所示。

图 2:NFC 协议族

在卡模拟模式下,NFC 模拟带有安全模块的 RFID 集成电路 (IC) 卡,允许用户安全购物。在点对点模式下,您可以通过 NFC 连接在不同的 NFC 设备之间共享信息,例如名片。您还可以通过 NFC 连接快速设置 WiFi* 或蓝牙* 连接,并通过 WiFi 或蓝牙连接传输大文件。在读写器模式下,您可以使用支持 NFC 的设备读取 NFC 标签并启动智能任务。

每种模式将在下面更详细地讨论。

NFC 卡模拟模式

NFC 模块通常由两部分组成:NFC 控制器和安全元件 (SE)。NFC 控制器负责通信。SE 负责加密和解密敏感数据。

图 3:NFC 硬件组件

SE 通过 SWP(单线协议)或 DCLB(数字非接触式桥接)总线连接到 NFC 控制器。NFC 标准定义了主机和控制器之间的逻辑接口,允许它们通过射频场进行通信。内置应用程序或小型操作系统实现 SE,负责敏感数据的加密和解密。

实现 SE 的三种解决方案是

  • 嵌入 SIM 卡
  • 嵌入 SD 卡
  • 嵌入 NFC 芯片

图 4:三种 NFC SE 解决方案

中国移动通信、沃达丰和 AT&T 等电信运营商通常更喜欢基于 SIM 卡的解决方案,他们鼓励用户免费将旧 SIM 卡更换为新的支持 NFC 的 SIM 卡。

NFC 点对点模式

两个支持 NFC 的设备可以轻松直接通信,共享名片等小文件。两个支持 NFC 的设备还可以相互共享配置的 .xml 文件,并建立蓝牙/WiFi 连接以共享大文件。在此模式下,不需要 SE 模块。

NFC 读写器模式

在此模式下,NFC 主机可以读/写 NFC 标签。一个很好的例子是阅读有用的

智能海报中的信息。用户可以访问链接查看广告和下载折扣券。

图 5:NFC 读写器模式

Android NFC 开发介绍

Android 通过两个包支持 NFC:android.nfc 和 android.nfc.tech。

android.nfc 包中的主要类是

NfcManager:Android 设备可用于管理所有指示的 NFC 适配器,但由于大多数 Android 设备只支持一个 NFC 适配器,因此 NfcManager 通常直接通过 getDefaultAdapter 调用以获取特定的手机适配器。

NfcAdapter:它作为 NFC 代理,类似于计算机中安装的网络适配器,手机通过它访问 NFC 硬件以启动 NFC 通信。

NDEF:NFC 标准定义了一种通用数据格式,称为 NFC 数据交换格式 (NDEF),它可以存储和传输各种项目,从任何 MIME 类型对象到超短 RTD 文档,例如 URL。NdefMessage 和 NdefRecord 是 NFC 论坛定义的两种 NDEF 数据格式,将在示例代码中使用。

Tag:Android 定义它表示标签、卡片等被动对象。当设备检测到标签时,Android 将创建一个标签对象,然后将其放入 Intent 对象中,最后将其发送到适当的 Activity。

android.nfc.tech 包还包含许多重要的子类。这些子类提供对标签技术功能(包括读写操作)的访问。根据所使用的技术类型,这些类分为不同的类别,例如:NfcA、NfcB、NfcF、MifareClassic 等。

当手机开启 NFC 并检测到 TAG 后,TAG 分发系统将自动创建一个包含 NFC TAG 信息的 intent 包。如果手机有多个应用程序可以处理此 intent,将弹出一个对话框询问用户选择哪个 TAG activity。TAG 分发系统定义了三种类型的 intent。它们按优先级降序排列

NDEF_DISCOVERED, TECH_DISCOVERED, TAG_DISCOVERED

这里我们使用 action intent-filter 类型来处理从 TECH_DISCOVERED 到 ACTION_TECH_DISCOVERED 的所有类型。文件 nfc_tech_filter.xml 用于文件中 TAG 定义的类型。有关详细信息,请参阅Android 文档。下图显示了手机检测到 TAG 时匹配过程的 Activity。

图 6:NFC 标签检测过程

案例研究:开发基于 NFC 的读写器应用程序

以下演示展示了 NFC 标签的读写器功能。在访问设备的 NFC 硬件并正确处理 NFC intent 之前,请在您的 AndroidManifest.xml 文件中声明这些项目

<uses-permission android:name="android.permission.NFC" />

您的应用程序必须支持的最低 SDK 版本是级别 10,因此请在您的 AndroidManifest.xml 文件中声明这些项目

<uses-sdk android:minSdkVersion="10"/>

In the onCreate function,you can apply the NfcAdapter:

public void onCreate(Bundle savedInstanceState) {
……
adapter = NfcAdapter.getDefaultAdapter(this);
……
}

以下 Intent 回调显示了读取器功能。如果系统广播 Intent 等于 NfcAdapter.ACTION_TAG_DISCOVERED,那么您可以读取标签中的信息并显示它。

@Override
	protected void onNewIntent(Intent intent){
		if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())){
		mytag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);  // get the detected tag
		Parcelable[] msgs =
intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
			NdefRecord firstRecord = ((NdefMessage)msgs[0]).getRecords()[0];
			byte[] payload = firstRecord.getPayload();
			int payloadLength = payload.length;
			int langLength = payload[0];
			int textLength = payloadLength - langLength - 1;
			byte[] text = new byte[textLength];
			System.arraycopy(payload, 1+langLength, text, 0, textLength);
			Toast.makeText(this, this.getString(R.string.ok_detection)+new String(text), Toast.LENGTH_LONG).show();
					}
	}

以下代码显示了写入器功能。在确定 mytag 的值之前,您必须知道是否检测到标签,然后将信息写入 mytag。

If (mytag==Null){
	……
}
else{
……
write(message.getText().toString(),mytag);
……
}
	private void write(String text, Tag tag) throws IOException, FormatException {
		NdefRecord[] records = { createRecord(text) };
		NdefMessage  message = new NdefMessage(records);
// Get an instance of Ndef for the tag.
		Ndef ndef = Ndef.get(tag); // Enable I/O
		ndef.connect(); // Write the message
		ndef.writeNdefMessage(message); // Close the connection
		ndef.close();
	}

根据从标签读取的信息,您可以执行更多操作,例如启动智能任务、访问网站等。

案例研究:开发使用 MifareClassic 卡的基于 NFC 的应用程序

在此演示中,我们使用 Mifare 卡进行数据读取测试,并使用卡的 TAG 类型 MifareClassic。MifareClassic 卡常用于许多场景,例如身份证、公交卡等。传统的 MifareClassic 卡的存储空间分为 16 个区域(扇区),每个区域有四个块(块),每个块可以存储 16 字节的数据。

每个区域的最后一个块称为 Trailer,主要用于存储用于读写数据的本地块密钥。它有两个密钥:A 和 B,每个密钥长度为 6 字节,默认值通常由 MifareClassic.KEY_DEFAULT 定义为全键 FF 或 0。

因此,在写入 Mifare 卡时,首先需要具有正确的密钥值(起到保护作用),并且在用户读写该区域的数据之前必须进行成功的身份验证。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"   
    package="org.reno"   
    android:versionCode="1"   
    android:versionName="1.0" >   
    <uses-permission android:name="android.permission.NFC" />   
    <uses-sdk android:minSdkVersion="14" />   
    <uses-feature android:name="android.hardware.nfc" android:required="true" />   
    <application   
        android:icon="@drawable/ic_launcher"   
        android:label="@string/app_name" >   
        <activity   
            android:name="org.reno.Beam"   
            android:label="@string/app_name"   
            android:launchMode="singleTop" >   
            <intent-filter>   
                <action android:name="android.intent.action.MAIN" />   
   
                <category android:name="android.intent.category.LAUNCHER" />   
            </intent-filter>   
            <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>  
    </application>   
</manifest>

res/xml/nfc_tech_filter.xml:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> 
    <tech-list> 
       <tech>android.nfc.tech.MifareClassic</tech> 
    </tech-list> 
</resources>

以下是读取 MifareClassic 卡的示例

     private void processIntent(Intent intent) {    
        Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);   
        for (String tech : tagFromIntent.getTechList()) {   
            System.out.println(tech);   
        }   
        boolean auth = false;   
        MifareClassic mfc = MifareClassic.get(tagFromIntent);   
        try {   
            String metaInfo = "";   
            //Enable I/O operations to the tag from this TagTechnology object.   
            mfc.connect();   
            int type = mfc.getType(); 
            int sectorCount = mfc.getSectorCount();   
            String typeS = "";   
            switch (type) {   
            case MifareClassic.TYPE_CLASSIC:   
                typeS = "TYPE_CLASSIC";   
                break;   
            case MifareClassic.TYPE_PLUS:   
                typeS = "TYPE_PLUS";   
                break;   
            case MifareClassic.TYPE_PRO:   
                typeS = "TYPE_PRO";   
                break;   
            case MifareClassic.TYPE_UNKNOWN:   
                typeS = "TYPE_UNKNOWN";   
                break;   
            }   
            metaInfo += "Card type:" + typeS + "n with" + sectorCount + " Sectorsn, "   
                    + mfc.getBlockCount() + " BlocksnStorage Space: " + mfc.getSize() + "Bn";   
            for (int j = 0; j < sectorCount; j++) {   
                //Authenticate a sector with key A.   
                auth = mfc.authenticateSectorWithKeyA(j,   
                        MifareClassic.KEY_DEFAULT);   
                int bCount;   
                int bIndex;   
                if (auth) {   
                    metaInfo += "Sector " + j + ": Verified successfullyn";   
                    bCount = mfc.getBlockCountInSector(j);   
                    bIndex = mfc.sectorToBlock(j);   
                    for (int i = 0; i < bCount; i++) {   
                        byte[] data = mfc.readBlock(bIndex);   
                        metaInfo += "Block " + bIndex + " : "   
                                + bytesToHexString(data) + "n";   
                        bIndex++;   
                    }   
                } else {   
                    metaInfo += "Sector " + j + ": Verified failuren";   
                }   
            }   
            promt.setText(metaInfo);   
        } catch (Exception e) {   
            e.printStackTrace();   
        }   
    }

摘要

配备 NFC 的智能手机让个人无需随身携带票根或停车证,即可将所需的一切掌握在指尖。该技术甚至可以与朋友连接,共享信息、玩游戏和传输数据。NFC 致力于兼顾工作和娱乐,这是其取得成功并在未来便利我们生活的关键因素。

关于作者

王松月和张亮是英特尔软件与服务集团的应用工程师,专注于移动应用赋能,包括 Android 应用开发和 x86 设备优化,以及 Web HTML5 应用开发。

其他相关文章和资源

© . All rights reserved.