赞
踩
一,简介
1.1 NFC是继wifi和蓝牙之后,又一种新的近距离无线传输技术,这种局限性比较大,设备必须装有NFC硬件才能实现数据传输,而且传输距离非常短,4cm之内才能传输,真实场景可能触碰才能传输。
1.2 NFC优缺点
优点:传输速度快;连接方便,触碰就能实现通信;安全性高
缺点:传输距离非常短;传输数据量小;并不是全部普及,部分手机不支持
1.3 NFC,蓝牙,红外对比
对比项 | NFC | 蓝牙 | 红外 |
网络类型 | 点对点 | 单点对多点 | 点对点 |
有效距离 | <=0.1m | <=10m,最新的蓝牙4.0有效距离可达100m | 一般在1m以内,热技术连接,不稳定 |
传输速度 | 最大424kbps | 最大24Mbps | 慢速115.2kbp5,快速4Mbps |
连接时间 | <0.1s | 6s | 0.5s |
安全性 | 安全,硬件实现 | 安全,软件实现 | 个安全,使用IRFM时除外 |
通信模式 | 主动-主动/被动 | 主动-主动 | 主动-主动 |
成本 | 低 | 中 | 低 |
1.4 NFC通信模式
读卡器模式(Reader/writer mode)、仿真卡模式(Card Emulation Mode)、点对点模式(P2P mode)。
读卡器模式
数据在NFC芯片中,可以简单理解成“刷标签”。本质上就是通过支持NFC的手机或其它电子设备从带有NFC芯片的标签、贴纸、名片等媒介中读写信息。通常NFC标签是不需要外部供电的。当支持NFC的外设向NFC读写数据时,它会发送某种磁场,而这个磁场会自动的向NFC标签供电。
仿真卡模式
数据在支持NFC的手机或其它电子设备中,可以简单理解成“刷手机”。本质上就是将支持NFC的手机或其它电子设备当成借记卡、公交卡、门禁卡等IC卡使用。基本原理是将相应IC卡中的信息凭证封装成数据包存储在支持NFC的外设中 。
在使用时还需要一个NFC射频器(相当于刷卡器)。将手机靠近NFC射频器,手机就会接收到NFC射频器发过来的信号,在通过一系列复杂的验证后,将IC卡的相应信息传入NFC射频器,最后这些IC卡数据会传入NFC射频器连接的电脑,并进行相应的处理(如电子转帐、开门等操作)。
点对点模式
该模式与蓝牙、红外差不多,用于不同NFC设备之间进行数据交换,不过这个模式已经没有有“刷”的感觉了。其有效距离一般不能超过4厘米,但传输建立速度要比红外和蓝牙技术快很多,传输速度比红外块得多,如过双方都使用Android4.2,NFC会直接利用蓝牙传输。这种技术被称为Android Beam。所以使用Android Beam传输数据的两部设备不再限于4厘米之内。
点对点模式的典型应用是两部支持NFC的手机或平板电脑实现数据的点对点传输,例如,交换图片或同步设备联系人。因此,通过NFC,多个设备如数字相机,计算机,手机之间,都可以快速连接,并交换资料或者服务。
二,NFC通信步骤
2.1 AndroidManifest.xml添加NFC使用权限,不用动态请求
- <!--NFC 相关权限-->
- <!--描述所需硬件特性-->
- <uses-feature
- android:name="android.hardware.nfc"
- android:required="true" />
- <uses-permission android:name="android.permission.NFC" />
2.2 添加NFC标签过滤,两种方式
方式一:AndroidManifest.xml的Activity标签添加xml配置
res目录下 新建xml文件夹,再新建nfc_tech_filter.xml文件
- <?xml version="1.0" encoding="utf-8"?>
- <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <!-- 可以处理所有Android支持的NFC类型 -->
- <tech-list>
- <tech>android.nfc.tech.IsoDep</tech>
- </tech-list>
- <tech-list>
- <tech>android.nfc.tech.NfcA</tech>
- </tech-list>
- <tech-list>
- <tech>android.nfc.tech.NfcB</tech>
- </tech-list>
- <tech-list>
- <tech>android.nfc.tech.NfcF</tech>
- </tech-list>
- <tech-list>
- <tech>android.nfc.tech.NfcV</tech>
- </tech-list>
- <tech-list>
- <tech>android.nfc.tech.Ndef</tech>
- </tech-list>
- <tech-list>
- <tech>android.nfc.tech.NdefFormatable</tech>
- </tech-list>
- <tech-list>
- <tech>android.nfc.tech.MifareUltralight</tech>
- </tech-list>
- <tech-list>
- <tech>android.nfc.tech.MifareClassic</tech>
- </tech-list>
- </resources>
activity标签配置该xml
- <activity
- android:name=".MainActivity"
- android:exported="true">
- <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>
方式二:初始化NFC时候动态配置标签
- /**
- * 初始化nfc设置
- */
- public static void NfcInit(Activity activity) {
- Intent intent = new Intent(activity, activity.getClass());
- intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
- mPendingIntent = PendingIntent.getActivity(activity, 0, intent, 0);
- //做一个IntentFilter过滤你想要的action 这里过滤的是ndef
- IntentFilter filter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
- try {
- filter.addDataType("*/*");
- } catch (IntentFilter.MalformedMimeTypeException e) {
- e.printStackTrace();
- }
- mTechList = new String[][]{{MifareClassic.class.getName()},
- {NfcA.class.getName()}};
- //生成intentFilter
- mIntentFilter = new IntentFilter[]{filter};
- }
2.3 创建NFC适配器
NFC所有的操作都是通过NfcAdapter完成的,创建NfcAdapter后,同时新建一个等待的PendingIntent,这个主要用于出发NFC打开该页面
- private NfcAdapter mNfcAdapter;
- private PendingIntent mPendingIntent;
- @Override
- protected void onStart() {
- super.onStart();
- mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
- mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass())
- .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
-
- }
2.4 在onResume中开启前台调度,来初始化NFC
- //在onResume中开启前台调度
- @Override
- protected void onResume() {
- super.onResume();
- //设定intentfilter和tech-list。如果两个都为null就代表优先接收任何形式的TAG action。也就是说系统会主动发TAG intent。
- if (mNfcAdapter != null) {
- mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null); //启动 }
- }
- }
2.5 在onNewIntent中处理由NFC设备传递过来的intent
-
- //在onNewIntent中处理由NFC设备传递过来的intent
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- processIntent(intent);
- }
2.6 处理读取过来的数据,包括卡ID(通常为设备序列号,16进制形式09:D1:E6:6B)
然后NFC卡其它信息不一定有,NFC卡标签这些信息可能是没有的,但序列号是一定有的,即NFC卡的唯一标识
- //这块的processIntent() 就是处理卡中数据的方法
- public void processIntent(Intent intent) {
- try {
- tvContent.setText("");
- // 检测卡的id
- String id = readNFCId(intent);
- // NfcUtils中获取卡中数据的方法
- String result = readNFCFromTag(intent);
- StringBuilder stringBuilder = new StringBuilder();
- stringBuilder.append("卡ID十六进制:" + id).append("\r\n");
- stringBuilder.append("卡ID十进制:" + hexToDec(id)).append("\r\n");
- stringBuilder.append("信息:").append("\r\n");
- stringBuilder.append(result).append("\r\n");
-
-
- tvContent.setText(stringBuilder);
-
- // 往卡中写数据
- //String data = "this.is.write";
- //writeNFCToTag(data, intent);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /**
- * 读取nfcID
- */
- public String readNFCId(Intent intent) throws UnsupportedEncodingException {
- Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
- String id = ByteArrayToHexString(tag.getId());
- return id;
- }
-
-
- /**
- * 读取NFC的数据
- */
- public String readNFCFromTag(Intent intent) throws UnsupportedEncodingException {
- Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
- StringBuilder stringBuilder = new StringBuilder();
- if (rawArray != null) {
- for (int i = 0; i < rawArray.length; i++) {
- NdefMessage mNdefMsg = (NdefMessage) rawArray[i];
-
- for (int j = 0; j < mNdefMsg.getRecords().length; i++) {
- NdefRecord mNdefRecord = mNdefMsg.getRecords()[j];
-
- if (mNdefRecord != null) {
- String readResult = new String(mNdefRecord.getPayload(), "UTF-8");
- stringBuilder.append(readResult).append("\r\n");
- }
- }
- }
- }
- return stringBuilder.toString();
- }
-
-
- /**
- * 十六进制转10进制
- * @param s
- * @return
- */
- public static int hexToDec(String s) {
- String s1 = s.toUpperCase(); // 全转大写
- char[] chars = s1.toCharArray(); // 转成 char 数组
- Stack<Character> stack = new Stack<>();
- for (int i = 0; i < chars.length; i++) {
- stack.push(chars[i]); // 放入栈中,倒序遍历
- }
- int sum = 0; // 定义总和
- int size = stack.size(); // 要先赋值给 size ,不然 stack.pop() 之后 size 会变
- for (int i = 0; i < size; i++) {
- Character pop = stack.pop();
- if (String.valueOf(pop).matches("[A-F]")) { // 如果是 A-F
- sum += (Math.pow(16, i) * ((pop - 55))); // A的ASCII码为 65,取偏移量
- } else { // 如果是纯数字
- sum += Math.pow(16, i) * Integer.parseInt(String.valueOf(pop));
- }
- }
- return sum;
- }
-
-
- /**
- * 将字节数组转换为字符串
- */
- private String ByteArrayToHexString(byte[] inarray) {
- int i, j, in;
- String[] hex = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F"};
- String out = "";
-
- for (j = 0; j < inarray.length; ++j) {
- in = (int) inarray[j] & 0xff;
- i = (in >> 4) & 0x0f;
- out += hex[i];
- i = in & 0x0f;
- out += hex[i];
- }
- return out;
- }
2.7 往NFC写入数据
- /**
- * 往nfc写入数据
- */
- public static void writeNFCToTag(String data, Intent intent){
- try {
- Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
- Ndef ndef = Ndef.get(tag);
- ndef.connect();
- NdefRecord ndefRecord = null;
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
- ndefRecord = NdefRecord.createTextRecord(null, data);
- }
- NdefRecord[] records = {ndefRecord};
- NdefMessage ndefMessage = new NdefMessage(records);
- ndef.writeNdefMessage(ndefMessage);
- }catch (Exception e){
-
- }
- }
- // 往卡中写数据
- String data = "this.is.write";
- writeNFCToTag(data, intent);
2.8 取消NfcAdapter调度
- @Override
- protected void onPause() {
- super.onPause();
- if (mNfcAdapter != null) {
- mNfcAdapter.disableForegroundDispatch(this);
- }
- }
2.9 销毁NfcAdapter
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mNfcAdapter = null;
- }
2.10 总结
NFC适合卡片类刷卡数据传输场景,比如门禁卡,支付卡,地铁卡等,快捷方便
三 NFC读卡器通信
3.1 一些手机是不支持NFC的,那么可以选择备选方案,读卡器usb接口插入手机使用。
3.2 但读卡器种类也有很多种,有些是支持键盘模式的,有些是支持usb通信模式的,还有些是支持串口,wifi通信模式。下面主要说下键盘模式,和usb模式通信
3.3 键盘模式比较简单,简单键盘输入事件就可以,大部分扫码枪,读卡器是支持这种模式的,蛀牙源码
- private StringBuffer KeyStringBuffer;
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- int unicodeChar = event.getUnicodeChar();
- String number = String.valueOf((char) unicodeChar);
- if (KeyStringBuffer == null) {
- KeyStringBuffer = new StringBuffer();
- }
-
- KeyStringBuffer.append(number);
-
- if (KeyStringBuffer != null && KeyStringBuffer.toString().length() >= 8) {
- //都取到的数据
- String resultString = KeyStringBuffer.toString();
-
- KeyStringBuffer = null;
-
- Log.e("EEE", "dispatchKeyEvent: " + resultString);
- .........自己业务
- }
- }
- return super.dispatchKeyEvent(event);
- }
3.4 USB模式,通过转接器连接手机,usb连接后可能通过读卡器内部协议来进行usb通信,所以需要读卡器厂的协议指令。下面是通用usb通信:
- public class MainActivity extends AppCompatActivity {
- private static final String TAG = "MainActivity";
- private static final String ACTION_USB_PERMISSION =
- "com.android.example.USB_PERMISSION";
-
- private UsbManager manager;
- private UsbDevice device;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
-
- }
-
-
- public void openUsbClick(View view) {
- initUsbManager();
- }
-
- /**
- * 初始化UsbManager
- */
- private void initUsbManager() {
- //获取UsbManager
- manager = (UsbManager) getSystemService(Context.USB_SERVICE);
-
- //查找设备
- HashMap<String, UsbDevice> deviceList = manager.getDeviceList();
- Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
- while (deviceIterator.hasNext()) {
- UsbDevice device = deviceIterator.next();
- Log.e(TAG, "onCreate: " + device.getDeviceName());
- requestPermission(device);
- }
-
-
- }
-
- /**
- * 请求权限
- */
- private void requestPermission(UsbDevice device) {
- //请求权限
- PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
- IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
- registerReceiver(usbReceiver, filter);
- manager.requestPermission(device, permissionIntent);
- }
-
- /**
- * 权限回调
- */
- private final BroadcastReceiver usbReceiver = new BroadcastReceiver() {
-
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (ACTION_USB_PERMISSION.equals(action)) {
- synchronized (this) {
- device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
- if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
- if (device != null) {
- //call method to set up device communication
- openDevice();
- }
- } else {
- Log.d(TAG, "permission denied for device " + device);
- }
- }
- }
- }
- };
-
- /**
- * 打开设备,接口数据
- */
- private static int TIMEOUT = 100;
- private boolean forceClaim = true;
- private UsbDeviceConnection connection;
- private UsbInterface usbInterface;
- private UsbEndpoint usbEndpoint;
- private void openDevice() {
- if (connection == null) {
- //打开设备
- connection = manager.openDevice(device);
- // 配置设备接口
- usbInterface = device.getInterface(0);
- connection.claimInterface(usbInterface, forceClaim);
- // 获取设备端点
- usbEndpoint= usbInterface.getEndpoint(0);
- readData();
- }
-
-
-
- //发送数据
- //byte[] dataToSend = "aa".getBytes(); // 需要发送的数据
- //int bytesSent = connection.bulkTransfer(usbEndpoint, dataToSend, dataToSend.length, TIMEOUT);
-
-
- }
-
- //读取数据
- boolean isReading = true;
- private void readData(){
- new Thread(new Runnable(){
- @Override
- public void run() {
- while (isReading){
- // 接收数据
- byte[] buffer = new byte[1024];
- int byteCount = connection.bulkTransfer(usbEndpoint, buffer, buffer.length, 1000);
- if (byteCount > 0) {
- // 读取到有效数据
- String data = new String(buffer, 0, byteCount);
- // 处理数据
- Log.e(TAG, "data: "+data );
- }
- }
- }
- }).start();
- }
-
- /**
- * 关闭设备
- */
- public void closeConnect() {
- if (connection != null) {
- connection.releaseInterface(usbInterface);
- connection.close();
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- closeConnect();
- }
-
- }
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。