NFC和RFID
RFID是射频识别技术,它主要是通过无线电讯号识别特定目标,并可读写数据,但仅仅是单向的读取。
RFID有低频(几mm的传输距离)、高频(13.56Mhz)、超高频(防碰撞算法、低功耗芯片设计、UHF电子标签天线设计、测试认证)、微波频段等,频段不同,导致功率不同,导致传输的距离不同。
NFC是近距离无线通讯技术,芯片具有相互通信能力,并有计算能力。NFC可以看作是RFID的子集,用的是RFID的高频(13.56MHz)的标准,但却是双向过程。
他们的区别基于两点。
首先,NFC技术增加了点对点通信功能,可以快速建立蓝牙设备之间的无线通信.NFC设备彼此寻
找对方进而建立通信连接。在通信模式上,NFC不同于RFID网络,后者是建立于主从关系之下,并且芯片以被动的方式通过昂贵的、需要能源支持的“读取”设备来读取。而NFC设备却能被设置为被动和主动两种模式,即使在设备关机的情况下(被动模式),仍然可以发送识别数据,也正是这一特点使其成为智能卡应用的理想选择。同时,它也可在主动模式下,与其他主动或被动的RFID设
备进行通信。
其次,NFC和RFID针对的应用不同,除了点对点通信的应用之外,NFC的主要应用是移动小额支付。NFC的应用针对移动性的特点,用于识别和数据交换,而RFID的主要用途是识别。
什么是NFC?
近距离无线通信技术(Near Field Communication,NFC)。
NFC提供了一种简单的、非触控式的解决方案,可以让消费者简单直观地交换信息、访问内容与服务。与wifi、蓝牙、红外线等数据传输技术的一个主要差异就是有效距离一般不能超过4cm。
NFC标签是什么?
其实就是一个小小的可以擦写输入的小芯片,我们可以将一些个性化的功能写进去。NFC标签怎么用呢?就是带有NFC芯片的手机通过扫描NFC标签,可以立刻响应标签里的功能,比如最简单的开启飞行模式。
14443A标签卡
MifareClass:
标准卡
MifareUltralight:
这类卡相对较小,不加密,成本也低,只有几百字节大小。
15693标签卡
NfcV
8字节UID,最后一字节固定为0xE0,需要发送写的命令串才能读。
命令列表,命令格式:标识 + 命令 + 参数 + 数据 + 校验
ISO10536,ISO15693,ISO14443的区别
ISO10536标准主要发展于1992到1995年间,由于这种卡的成本高,与接触式IC卡相比优点很少,因此这种卡从未在市场上销售。
ISO14443和ISO15693标准在1995年开始操作,单个系统于1999年进入市场,两项标准的完成则是在2000年之后。二者皆以13.56MHz交变信号为载波频率:ISO15693读写距离较远,当然这也与应用系统的天线形状和发射功率有关;而ISO 14443 读写距离稍近,但应用较广泛,目前的第二代电子身份证采用的标准是ISO 14443 TYPE B协议。
ISO14443定义了TYPE A、TYPE B两种类型协议。通信速率为106kbits/s,它们的不同主要在于载波的调制深度及位的编码方式。
4443B和15693最大的区别可能是他们的读写速度14443B一般是106Kb/s及以上,而15693一般上限是53或者26.5Kb/s,用通讯速率换取读取范围,使得他们的应用有很大不同
还有很多其他的区别,如防冲突机制、信源信道编码方式、通讯协议等等
MF RC531不能读取ISO15693,如果单纯的读取ISO15693,可以选择SL RC400
The minimum operating field strength(最低工作场强)is specified:
ISO14443:Hmin= 1.5 A/m(Mifare)
ISO15693: Hmin = 0.15 A/m(I*Code)
也就是说,ISO15693标准的灵敏度是ISO14443的10倍,这应该是主要区别之一。
是说15693的距离更远一些,
14443更成熟,加密性更好用在保密性更好的地方
15693是开放的
https://blog.csdn.net/obanaganastar/article/details/51491105
NFC支持3种工作模式
1.读卡器模式;
2.仿真卡模式;
3.点对点模式;
1.读卡器模式:
通过NFC设备(支持NFC的Android手机)从带有NFC芯片的标签、贴纸、报纸、明信片等媒介读取信息,或将数据写到这些媒介中。
2.仿真卡模式:
是将支持NFC的手机或其他电子设备当成借记卡、信用卡、公交卡、门禁卡等IC卡使用;基本原理是将相应的IC卡中的信息(支付凭证)封装成数据包存储在支持NFC的手机中,在使用时还需要一个NFC射频器(相当于刷传统IC卡时使用的刷卡器),将手机靠近NFC射频器,手机就会收到NFC射频器发过来的信号,在通过一系列复杂的验证后,将IC卡的相应信息传入NFC射频器,最后这些IC卡数据会传入NFC射频器连接的计算机,并进行相应的处理(如电子转账、开门等操作)。
3.点对点模式:
与蓝牙、红外差不多,可以用于不同的NFC设备之间进行数据交换,只是NFC的点对点模式有效距离更短,不能超过4cm;但是如果两个设备使用的都是Android4.2及以上版本,NFC会直接利用蓝牙传输,这种技术被称为Android Beam,所以Android Beam传输数据的两部设备不局限于4cm之内。
基础知识
- Android SDK API主要支持NFC论坛标准(Forum Standard),这种标准被称为NDEF(NFC Data Exchange Format,NFC数据交换格式);
- Android SDK API支持如下三种NDEF数据的操作:
a.从NFC标签读取NDEF格式的数据;
b.向NFC标签写入NDEF格式的数据;
c.通过Android Beam技术将NDEF数据发送到另一部NFC设备; - 在一个NFC设备读取NFC标签或另一个NFC设备中的数据之前会在0.1秒的时间之内建立NFC连接,然后数据会自动从被读取一端流向读取数据的一端;数据接收端会根据具体的数据格式和标签类型调用相应的Activity(这种行为也称为Tag Dispatch),这些Activity都需要定义Intent Filter,这些Intent Filter中就会指定不同的过滤机制,分为三个级别,也称为NFC的三重过滤机制。
a.NDEF_DISCOVERED:
只过滤固定格式的NDEF数据。例如:纯文本、指定协议(http、ftp、smb等)的URI等;
b.TECH_DISCOVERED:
当ACTION_NDEF_DISCOVERED指定的过滤机制无法匹配Tag时,就会使用这种过滤机制进行匹配,这种过滤机制并不是通过Tag中的数据格式进行匹配的,而是根据Tag支持的数据存储格式进行匹配,因此这种过滤机制的范围更广;
c. TAG_DISCOVERED:
如果将NFC过滤机制看成if…else if…else语句的话,那么这种过滤机制就相当于else部分,当前面两种过滤机制都匹配失败后,系统就会利用这种过滤机制来处理,这种过滤机制用来处理未识别的Tag(数据格式不对,而且Tag支持的格式也不匹配)。 - Android系统会依次匹配NDEF_DISCOVERED、TECH_DISCOVERED和TAG_DISCOVERED;如果通过三重过滤机制仍然无法匹配Tag,则什么都不做;通常在成功匹配Tag后,Android设备会发出比较清脆的声音,而未成功匹配Tag,就会发出比较沉闷的声音。
Android中的NFC
- 获取NFC权限
<uses-permission android:name="android.permission.NFC" />
- 获取默认的NFC控制器,并进行判断
private static NfcAdapter nfcAdapter;//NFC适配器
...
...
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
Log.d("h_bl", "No support NFC!");
Toast.makeText(getApplicationContext(), "No support NFC!", Toast.LENGTH_SHORT).show();
return;
}
if (!nfcAdapter.isEnabled()) {
Toast.makeText(getApplicationContext(), "Please enable the NFC function first in the system settings!", Toast.LENGTH_SHORT).show();
Log.d("h_bl", "请在系统设置中先启用NFC功能!");
}
- 捕获NFC Intent
mIntent = this.getIntent();
- 在onCreate()方法中,创建一个PendingIntent对象
// NFC前台调度系统
private PendingIntent pendingIntent = null;
...
......
// 初始化PendingIntent,当有NFC设备连接上的时候,就交给当前Activity处理
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
- onPause(),onResume(),onNewIntent()方法中添加如下代码
@Override
protected void onPause() {
if (nfcAdapter != null)
nfcAdapter.disableForegroundDispatch(this);
super.onPause();
}
@Override
protected void onResume() {
if (nfcAdapter != null)
nfcAdapter.enableForegroundDispatch(this, pendingIntent, filters, tenchlists);
super.onResume();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// 当前app正在前端界面运行,这个时候有intent发送过来,那么系统就会调用onNewIntent回调方法,将intent传送过来
// 我们只需要在这里检验这个intent是否是NFC相关的intent,如果是,就调用处理方法
Log.d("h_bl", "onNewIntent");
praseIntent(intent); //处理Intent
}
- 关键步骤:onResume()函数中有两个参数还未补充:filters和techLists,在onCreate()中声明
public String[][] tenchlists;
public IntentFilter[] filters;
...
.......
// 声明前台activity能处理的NFC标签技术的数组
tenchlists = new String[][] { { IsoDep.class.getName() }, { NfcV.class.getName() }, { NfcF.class.getName() }, };
// 前台activity过滤获得所有的ACTION_TECH_DISCOVERED的intent
try {
filters = new IntentFilter[] { new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED, "*/*") };
} catch (MalformedMimeTypeException e1) {
e1.printStackTrace();
主要代码
- UUIDActivity
package com.example.yjw.NFC;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import android.nfc.tech.MifareClassic;
import android.nfc.tech.MifareUltralight;
import android.nfc.tech.NfcA;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.example.yjw.NFC.mifare.StringUtils;
import com.example.yjw.myviewpager.R;
import java.util.ArrayList;
import butterknife.BindView;
import butterknife.ButterKnife;
/**
* NFC-A,B NFC卡片读取
*/
public class UUIDActivity extends AppCompatActivity {
@BindView(R.id.listview)
ListView listview;
private Intent mIntent = null;
private static NfcAdapter nfcAdapter;
private static PendingIntent mPendingIntent;
private static IntentFilter[] mFilters;
private static String[][] mTechLists;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_uuid);
ButterKnife.bind(this);
//获取默认的NFC控制器,并进行判断
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
Log.d("h_bl", "No support NFC!");
Toast.makeText(getApplicationContext(), "No support NFC!", Toast.LENGTH_SHORT).show();
return;
}
if (!nfcAdapter.isEnabled()) {
Toast.makeText(getApplicationContext(), "Please enable the NFC function first in the system settings!", Toast.LENGTH_SHORT).show();
Log.d("h_bl", "请在系统设置中先启用NFC功能!");
}
//启用一个PendingIntent
/*mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
getClass()), 0);*/
mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
//intent匹配NfcAdapter的活动
// 前台activity过滤获得所有的ACTION_TECH_DISCOVERED的intent
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
try {
ndef.addDataType("*/*");
} catch (IntentFilter.MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
mFilters = new IntentFilter[]{ndef};
//设置IsoDep,MifareClassic,MifareUltralight
// 声明前台activity能处理的NFC标签技术的数组
mTechLists = new String[][]{new String[]{IsoDep.class.getName()},
new String[]{MifareUltralight.class.getName()}, new String[]{MifareClassic.class.getName()}};
//捕获NFC Intent
mIntent = this.getIntent();
ReadCardSN();
}
private void ReadCardSN() {
// 解析该Intent的Action
String action = mIntent.getAction();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {//当前的action
//获取标签tag
Tag tag = mIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
//获取NFC卡的唯一值
byte[] bytCardSN = tag.getId();
String strCardSN = StringUtils.bytesToHexString(bytCardSN);
//调用getTechList()方法来确定该tag能支持的技术
String[] arTeachList = tag.getTechList();
NfcA nfcA = NfcA.get(tag);
byte[] bytAtqa = nfcA.getAtqa();
short Sak = nfcA.getSak();
int maxTranLen = nfcA.getMaxTransceiveLength();
String strAtqa = StringUtils.bytesToHexString(bytAtqa);
String strSAK = String.format("%02X", Sak);
String strCardType;
if (Sak == 0x08) {
strCardType = "M1 card";
} else if (Sak == 0x20) {
strCardType = "CPU card";
} else if (Sak == 0x28 || Sak == 0x38) {
strCardType = "Composite card";
} else {
strCardType = "Unknown type";
}
ArrayList<String> blockData = new ArrayList<>();
blockData.add("NFC卡唯一值");
blockData.add(">" + strCardSN);
blockData.add("提供的功能");
for (int i = 0; i < arTeachList.length; i++) {
String strTeach = arTeachList[i];
blockData.add(">" + strTeach);
}
blockData.add("ATQA");
blockData.add(">" + strAtqa);
blockData.add("SAK");
blockData.add(">" + strSAK + " " + strCardType);
blockData.add("Max transmission length");
blockData.add(">" + maxTranLen);
//---------------------显示输出---------------------
String[] contents = new String[blockData.size()];
blockData.toArray(contents);
listview.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, contents));
} else {
showAlert("Do not find card");
}
}
/**
* 显示对话框
*
* @param alertCase
*/
private void showAlert(String alertCase) {
// prepare the alert box
AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
alertbox.setMessage(alertCase);
// set a positive/yes button and create a listener
alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() {
// Save the data from the UI to the database - already done
public void onClick(DialogInterface arg0, int arg1) {
//clearFields();
}
});
// display box
alertbox.show();
}
@Override
protected void onPause() {
if (nfcAdapter != null)
nfcAdapter.disableForegroundDispatch(this);
super.onPause();
}
@Override
protected void onResume() {
//mFilters,前台调度系统activity能过滤的nfc标签,重写能调度的nfc标签过滤器,或者总是填null。
//mTechLists,应用程序希望处理的NFC标签技术的数组
//如果filters和techLists参数均为空,则会导致前台activity通过ACTION_TAG_DISCOVERED intent接收所有的标签。
if (nfcAdapter != null)
//-----------------非常关键,必要的哦,不能删除----------------
nfcAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters,
mTechLists);
super.onResume();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
// 当前app正在前端界面运行,这个时候有intent发送过来,那么系统就会调用onNewIntent回调方法,将intent传送过来
// 我们只需要在这里检验这个intent是否是NFC相关的intent,如果是,就调用处理方法
Log.d("h_bl", "onNewIntent");
mIntent = intent;
ReadCardSN(); //处理Intent
}
}
- StringUtils
package com.example.yjw.NFC.mifare;
/**
* Created by Administrator on 2018/7/26.
*/
public class StringUtils {
/*
byte[] --> 16 hex string
*/
public static String bytesToHexString(byte[] src) {
StringBuilder stringBuilder = new StringBuilder();
if (src == null || src.length <= 0) {
return null;
}
char[] buffer = new char[2];
for (int i = 0; i < src.length; i++) {
buffer[0] = Character.forDigit((src[i] >>> 4) & 0x0F, 16);
buffer[1] = Character.forDigit(src[i] & 0x0F, 16);
System.out.println(buffer);
stringBuilder.append(buffer);
}
return stringBuilder.toString();
}
/*
16 hex string--->byte[]
*/
public static byte[] hexStringToByte(String hex) {
int len = (hex.length() / 2);
byte[] result = new byte[len];
char[] achar = hex.toCharArray();
for (int i = 0; i < len; i++) {
int pos = i * 2;
result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
}
return result;
}
private static int toByte(char c) {
byte b = (byte) "0123456789ABCDEF".indexOf(c);
return b;
}
}
- activity_uuid.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical"
tools:context="com.example.yjw.NFC.UUIDActivity">
<ListView
android:id="@+id/listview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"></ListView>
</LinearLayout>
来源:CSDN
作者:小猪猪与二哈
链接:https://blog.csdn.net/qq_36298494/article/details/82985878