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





0/5 (0投票)
本文介绍了当前市场中基于 NFC 的技术和使用模式。然后,它还描述了如何在 Android 应用程序中使用 NFC。最后,它提出了两个案例研究,说明如何开发基于 NFC 的读写器应用程序。
引言
NFC(近场通信)是一种基于标准的短距离无线连接技术,可实现电子设备之间简单直观的双向交互。在两个 NFC 设备之间进行接触和通信非常方便。例如,借助智能手机集成的 NFC 技术,您可以轻松地触碰手机进行购物、分享名片、下载折扣券等等。未来将开发出许多基于 NFC 的新用途。
本文介绍了当前市场中基于 NFC 的技术和使用模式。然后,它还描述了如何在 Android 应用程序中使用 NFC。最后,它提出了两个案例研究,说明如何开发基于 NFC 的读写器应用程序。
NFC 技术架构
NFC 基于 13.56 MHz 的 RFID 技术,典型工作距离可达 10 厘米。数据交换速率高达 424 千比特/秒。与其他通信技术相比,NFC 最大的优势在于其使用快速简便。下图比较了 NFC 与其他通信技术。
NFC 技术有三种模式:NFC 卡模拟模式、点对点模式和读写器模式,如下图所示。
在卡模拟模式下,NFC 模拟带有安全模块的 RFID 集成电路 (IC) 卡,允许用户安全购物。在点对点模式下,您可以通过 NFC 连接在不同的 NFC 设备之间共享信息,例如名片。您还可以通过 NFC 连接快速设置 WiFi* 或蓝牙* 连接,并通过 WiFi 或蓝牙连接传输大文件。在读写器模式下,您可以使用支持 NFC 的设备读取 NFC 标签并启动智能任务。
每种模式将在下面更详细地讨论。
NFC 卡模拟模式
NFC 模块通常由两部分组成:NFC 控制器和安全元件 (SE)。NFC 控制器负责通信。SE 负责加密和解密敏感数据。
SE 通过 SWP(单线协议)或 DCLB(数字非接触式桥接)总线连接到 NFC 控制器。NFC 标准定义了主机和控制器之间的逻辑接口,允许它们通过射频场进行通信。内置应用程序或小型操作系统实现 SE,负责敏感数据的加密和解密。
实现 SE 的三种解决方案是
- 嵌入 SIM 卡
- 嵌入 SD 卡
- 嵌入 NFC 芯片
中国移动通信、沃达丰和 AT&T 等电信运营商通常更喜欢基于 SIM 卡的解决方案,他们鼓励用户免费将旧 SIM 卡更换为新的支持 NFC 的 SIM 卡。
NFC 点对点模式
两个支持 NFC 的设备可以轻松直接通信,共享名片等小文件。两个支持 NFC 的设备还可以相互共享配置的 .xml 文件,并建立蓝牙/WiFi 连接以共享大文件。在此模式下,不需要 SE 模块。
NFC 读写器模式
在此模式下,NFC 主机可以读/写 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。
案例研究:开发基于 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 应用开发。
其他相关文章和资源
- Gayathri Murali 的《Intel 平台上的 Android》 - Bay Area Android Fest
- Intel® Atom™ x86 镜像 for Android* 4.4 KitKat 安装说明 - 手动
- 编码 Android* 游戏应用以支持 Intel x86?这里有一些示例!
- Intel for Android* 开发者学习系列 #7:为 Intel® 架构创建和移植基于 NDK 的 Android* 应用程序
- 使用案例研究进行 Android* 上的 NFC 应用开发
- 在 Android* 商业应用程序中实现地图和地理围栏功能
- 自动 Android* 应用程序测试
- 如何在 Intel 架构上优化您的 Android* 应用 (NDK) - 两分钟搞定
- 如何设置 NDK 项目以编译适用于多个目标平台的应用