IC卡 (Integrated Circuit Card,集成电路卡)
有些国家和地区也称智能卡(smart card)、智慧卡(intelligent card)、微电路卡(microcircuit card)或微芯片卡等。它是将一个微电子芯片嵌入符合ISO 7816标准的卡基中,做成卡片形式。所以非接触式IC卡又被称为射频卡或者电子标签。IC卡是指集成电路卡,一般用的公交车卡就是IC卡的一种,也应用在门禁管理、身份证明和电子钱包。IC卡有别于磁卡,所以说IC卡消磁纯属伪科学!简单来说,其工作原理就是读卡器发射一个根据信息变化的电磁波。卡片内部的感应线圈把这个电磁波转换成感应电流,用以传递信息和驱动芯片工作。
射频识别即RFID(Radio
Frequency IDentification)
又称电子标签、无线射频识别,是一种通信技术,可通过无线电讯号识别特定目标并读写相关数据,而无需识别系统与特定目标之间建立机械或光学接触。常用的有低频(125k~134.2K)、高频(13.56Mhz)、超高频,无源等技术。RFID读写器也分移动式的和固定式的,目前RFID技术应用很广,如:图书馆,门禁系统,食品安全溯源等。
NFC是Near
Field Communication缩写,即近距离无线通讯技术。
由飞利浦公司和索尼公司共同开发的NFC是一种非接触式识别和互联技术,可以在移动设备、消费类电子产品、PC
和智能控件工具间进行近距离无线通信。NFC 提供了一种简单、触控式的解决方案,可以让消费者简单直观地交换信息、访问内容与服务。
以上介绍我们可以知道IC卡是一种存储数据的卡,而RFID是一种通讯技术,IC卡属于RFID的一种物理形式。NFC是由RFID演变出来的,向下兼容RFID,自然也兼容IC卡。
NFC是一套短距离的无线通信,通常距离是4厘米或更短。NFC工作频率是13.56M Hz,传输速率是106kbit/s 到848kbit/s. NFC总是在一个发起者和一个被动目标之间发生。发起者发出近场无线电波,这个近场可以给被动目标供电。这些被动的目标包括不需要电源的标签,卡,也可以是有电源的设备。
与其他无线通信技术比较, 例如蓝牙和WiFi, NFC提供更低贷款和距离,并且低成本,不需要供电,不需要实现匹配,整个通信过程仅仅是短短的靠近一秒就能完成。
一个带有NFC支持的android设备通常是一个发起者。也可以作为NFC的读写设备。他将检测NFC tags并且打开一个Activity来处理. Android 2.3.3还有支持有限的P2P。
Tags分很多种,其中简单的只提供读写段,有的只能读。复杂的tags可以支持一些运算,加密来控制对tags里数据段的读写。甚至一些tags上有简单的操作系统,允许一些复杂的交互和可以执行一些代码。
本文的代码例子是基于API10的。
要在Android手机中使用NFC,必须在AndroidManifest.xml中如下配置:
<uses-feature android:name="android.hardware.nfc"
android:required="true" />
<uses-permission android:name="android.permission.NFC" />
Tag发布系统
当android设备扫描到一个NFC tag,通用的行为是自动找最合适的Activity会处理这个tag Intent而不需要用户来选择哪个Activity来处理。因为设备扫描NFC tags是在很短的范围和时间,如果让用户选择的话,那就有可能需要移动设备,这样将会打断这个扫描过程。你应该开发你只处理需要处理的tags的Activity,以防止让用户选择使用哪个Activity来处理的情况。Android提供两个系统来帮助你正确的识别一个NFC tag是否是你的Activity想要处理的:Intent发布系统和前台Activity发布系统。
Intent发布系统检查所有Activities的intent filters,找出那些定义了可以处理此tag的Activity,如果有多个Activity都配置了处理同一个tag Intent,那么将使用Activity选择器来让用户选择使用哪个Activity。用户选择之后,将使用选择的Activity来处理此Intent.
前台发布系统允许一个Activity覆盖掉Intent发布系统而首先处理此tag Intent,这要求你将要处理Tag Intent的Activity运行在前台,这样当一个NFC tag被扫描到,系统先检测前台的Activity是否支持处理此Intent,如果支持,即将此Intent传给此Activity,如果不支持,则转到Intent发布系统。
以前台前台发布系统为例,需要编写如下代码:
1. 定义变量
private NfcAdapter mAdapter;
private String[][] techList;
private IntentFilter[] intentFilters;
private PendingIntent pendingIntent;
private Tag tag;
2. 添加下列代码到Activity的onCreate() 方法里:
//获取nfc适配器
mAdapter = NfcAdapter.getDefaultAdapter(
this);
//定义程序可以兼容的nfc协议,例子为nfca和nfcv
//在Intent filters里声明你想要处理的Intent,一个tag被检测到时先检查前台发布系统,
//如果前台Activity符合Intent filter的要求,那么前台的Activity的将处理此Intent。
//如果不符合,前台发布系统将Intent转到Intent发布系统。如果指定了null的Intent filters,
//当任意tag被检测到时,你将收到TAG_DISCOVERED intent。因此请注意你应该只处理你想要的Intent。
techList =
new String[][] {
new String[] { android.nfc.tech.NfcV.
class.getName() },
new String[] { android.nfc.tech.NfcA.
class.getName() } };
intentFilters =
new IntentFilter[] {
new IntentFilter(
NfcAdapter.ACTION_TECH_DISCOVERED), };
//创建一个 PendingIntent 对象, 这样Android系统就能在一个tag被检测到时定位到这个对象
pendingIntent = PendingIntent.getActivity(
this, 0,
new Intent(
this,
getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
3. 在onNewIntent方法中:
public void onNewIntent(Intent intent) {
tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
return;
}
4. 在OnPause方法中:
@Override
protected void onPause() {
super.onPause();
mAdapter.disableForegroundDispatch(
this);
}
4. 在OnResume方法中:
@Override
protected void onResume() {
super.onResume();
//使用前台发布系统
mAdapter.enableForegroundDispatch(
this, pendingIntent, intentFilters,
techList);
}
}
定义了这些方法以后,运行程序,在不锁屏的情况下,使用NFCV或NFCA的NFC卡靠近的手机的时候OnNewIntent就会被触发。Tag就可以被获取到,可以使用获取到的TAG来查询该卡的一些详细信息和数据。
http://www.cnblogs.com/haoxinyue/archive/2012/05/03/2479599.html
先了解一下MifareClassic协议
在android sdk 的文档中,描述道 “all
MifareClassic
I/O operations will be supported, and
MIFARE_CLASSIC
NDEF
tags will also be supported. In either case,
NfcA
will also be enumerated on the tag, because
all MIFARE Classic tags are also
NfcA
.” 所以说NFCA协议是兼容MifareClassic 协议的, 我们可以通过NfcA在android的相关类来处理给予MifareClassic
的RFID卡。
一般来说,给予MifareClassic的射频卡,一般内存大小有3种:
1K: 16个分区(sector),每个分区4个块(block),每个块(block) 16个byte数据
2K: 32个分区,每个分区4个块(block),每个块(block) 16个byte数据
4K:64个分区,每个分区4个块(block),每个块(block) 16个byte数据
对于所有基于MifareClassic的卡来说,每个区最后一个块叫Trailer,16个byte, 主要来存放读写该区的key,可以有A,B两个KEY,每个key长6byte,默认的key一般是FF 或 0,最后一个块的内存结构如下:
Block 0 Data 16bytes
Block 1 Data 16 bytes
Block 2 Data 16 bytes
Block 3 Trailer 16 bytes
Trailer:
Key A: 6 bytes
Access Conditions: 4 bytes
Key B: 6 bytes
所以在写卡的内存的时候,一般不能写每个sector的最后一个block,除非你有要修改KEY和访问权限的需求。如果KEY A 被你不小心修改掉了,而你不知道修改成什么,那与之对应的那个sector你就没有办法访问了。因为在MifareClassic中,如果你要读取数据,那么必须要有这个数据地址所在的sector的权限,这个权限就是这个sector的trailer的keyA或KEY B。
读数据的例子:
//tag 就是在上一篇中onNewIntent中获取的tag
MifareClassic mc = MifareClassic.get(tag);
short startAddress = 0;
short endAddress = 5;
byte[] data =
new byte[(endAddress - startAddress + 1 ) * ByteCountPerBlock];
try {
mc.connect();
for (
short i = startAddress; i <= endAddress; i++ ,time++) {
boolean auth =
false;
short sectorAddress = getSectorAddress(i);
auth = mc.authenticateSectorWithKeyA(sectorAddress, MifareClassic.KEY_DEFAULT);
if (auth){
//the last block of the sector is used for KeyA and KeyB cannot be overwritted
short readAddress = (
short)(sectorAddress == 0 ? i : i + sectorAddress);
byte[] response = mc.readBlock(readAddress);
CombineByteArray(data, response, time * ByteCountPerBlock);
}
else{
throw new NfcException(NfcErrorCode.TemporaryError,
"Authorization Error.");
}
}
mc.close();
}
catch (NfcException ne) {
throw ne;
}
catch (IOException e) {
throw new NfcException(NfcErrorCode.TemporaryError,
"Get response, what it is not successfully.", e);
}
finally
{
try {
mc.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
写数据的例子:
//tag 就是在上一篇中onNewIntent中获取的tag
MifareClassic mc = MifareClassic.get(tag);
try {
mc.connect();
boolean auth =
false;
short sectorAddress = 0
auth = mc.authenticateSectorWithKeyA(sectorAddress,
MifareClassic.KEY_DEFAULT);
if (auth) {
//the last block of the sector is used for KeyA and KeyB cannot be overwritted
mc.writeBlock(readAddress, dataTemp);
mc.close();
}
}
finally
{
try {
mc.close();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
完整的代码示例在
这里下载