菜鸟进场,方圆十里,寸草不生

这两天研究了NFC功能,网上查了很多的资料,不过感觉别人讲的都大同小异,但都缺了那么一点点火候,因为第一次接触有些概念是不清楚的,所以代码看上去很吃力,这个博客呢就是想整体的进行讲解一下,做一点点补充,算是做个笔记吧。

我用到的是nxp公司的S50芯片,网上也有很多卖的,但是叫法不一样,有的人叫M1智能卡芯片,有的叫复旦芯片(复旦什么科技公司生产的完全兼容S50的卡,可以理解为国产山寨),一般淘宝上买的都是这些,生活中使用的比如电梯卡,门禁卡也可能是属于这一类,价格大概5毛一张吧。

好了,先讲讲基本的东西吧

首先:
RFID: 叫射频识别技术,分为接触式(需要插卡)与非接触式(只需刷卡),NFC就是从这个技术发展而来的,包含多个频段,915MHz,125KHz,13.56MHz,2.4GHz等。
ID卡: 主要工作在125KHz,只有一个身份识别码,判断方式就是卡身有一串卡号,使用时需要联网进行操作。
IC卡: 主要工作在13.56MHz,里面有存储空间,可以进行读写,脱机工作(公交卡,门禁卡等)。
NFC: 叫近场通讯技术,只能工作在13.56MHz,所以能读取全部工作在这个频段的卡,是属于REID技术的,但是又有新的功能,可以理解为REID的子类。

以上概念了解了吧,所以我们开发NFC的话,只要不是设备与设备通信的话,那剩下的就是NFC来读取13.56MHz频段的IC卡或者ID卡。哦,还有NFC标签,这个我没有研究过,如果要用到这个的话就只有自己查了,这个靶向性比较好,容易查。

好吧,接下来说13.56频段的IC卡,由于不同的厂家生产的不同的芯片,数据格式与通信协议是不同的,所以需要对应,Android在这方面是有完整的底层支持的,你看到的NfcA、NfcB、NfcF、NfcV、IsoDep、Ndef这些就是对应不同的数据格式或者通讯协议的。举个例子吧,nxp公司的MIFARE Classic数据格式就是NfcA,MIFARE DESFire数据格式是IsoDep,二代身份证用的就是NfcB,Sony生产的Felica用的就是NfcF,德州仪器的VicinityCard卡用的是NfcV,。大概有个了解,在开发时通过自己手上的芯片类型再去定向搜索使用方法要容易一些。

好了,下面说我手上的MIFARE Classic S50芯片,读取所用到的类为MifareClassic,存储大小是1k,分16个扇区,每个扇区有4个块,每个块可以存储16个字节的数据。程序员一般从0开始数,第0扇区的第0块是厂家信息,这个无法写入。然后每个扇区的最后一个块(就是第3块)为密码块,每个密码块包含6个字节的密码A,4个字节的控制位(我现在手上只有一种卡,我不知道其他卡的控制位是否一样,但是按道理可能也许大概是一样的吧),6个字节的密码B,密码位是可以进行写入的,就是说可以自由设置扇区密码,一般新买的卡都是白卡,默认密码位ff ff ff ff ff ff(16进制)。可能不太清楚,截个图。

数据结构基本了解,下面开始讲解如何进行读取与写入:

读取:
添加权限

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

设置页面属性和添加过滤器(本来还有一个什么过滤文件的,结果我死活加不上去,那就这样吧,不加了)

<activityandroid:name=".NFCTest.NfcTestActivity"android:launchMode="singleTask"><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.NDEF_DISCOVERED" /></intent-filter><intent-filter><action android:name="android.nfc.action.TAG_DISCOVERED" /><category android:name="android.intent.category.DEFAULT" /></intent-filter><intent-filter><action android:name="android.nfc.action.TECH_DISCOVERED" /></intent-filter></activity>

行,页面配置好了就可以进行页面的编写了。

首先进行判断,是否能否有NFC功能,如果有的话是否打开。

NfcAdapter adapter = NfcAdapter.getDefaultAdapter(this);if (null == adapter) {Toast.makeText(this, "不支持NFC功能", Toast.LENGTH_SHORT).show();} else if (!adapter.isEnabled()) {Intent intent = new Intent(Settings.ACTION_NFC_SETTINGS);// 根据包名打开对应的设置界面startActivity(intent);}

重写onNewIntent方法,每次刷卡的时候都会进入这个方法的。然后再这个方法里操作是读是写。

好,先看如何进行读取,我把注释都写代码里,方便一点。

             //拿来装读取出来的数据,key代表扇区数,后面list存放四个块的内容Map<String, List<String>> map = new HashMap<>();//intent就是onNewIntent方法返回的那个intentTag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);MifareClassic mfc = MifareClassic.get(tag);//如果当前IC卡不是这个格式的mfc就会为空if (null != mfc) {try {//链接NFCmfc.connect();//获取扇区数量int count = mfc.getSectorCount();//用于判断时候有内容读取出来boolean flag = false;for (int i = 0; i < count; i++) {//默认密码,如果是自己已知密码可以自己设置byte[] bytes = {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};//验证扇区密码,否则会报错(链接失败错误)//这里验证的是密码A,如果想验证密码B也行,将方法中的A换成B就行boolean isOpen = mfc.authenticateSectorWithKeyA(i, bytes);if (isOpen) {//获取扇区里面块的数量int bCount = mfc.getBlockCountInSector(i);//获取扇区第一个块对应芯片存储器的位置//(我是这样理解的,因为第0扇区的这个值是4而不是0)int bIndex = mfc.sectorToBlock(i);for (int j = 0; j < bCount; j++) {//读取数据,这里是循环读取全部的数据//如果要读取特定扇区的特定块,将i,j换为固定值就行byte[] data = mfc.readBlock(bIndex+j);list.add(byteToString(data));}flag = true;}map.put(i + "", list);}if (flag) {//回调,因为我把方法抽出来了callback.callBack(map);} else {callback.error();}} catch (Exception e) {callback.error();e.printStackTrace();} finally {try {mfc.close();} catch (IOException e) {e.printStackTrace();}}}

byteToString()方法,就是将16进制的数据转为字符串。

/*** 将byte数组转化为字符串** @param src* @return*/public static String byteToString(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();}

接下来就是写数据了 a是扇区,b是块

     Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);MifareClassic mfc = MifareClassic.get(tag);byte[] data = new byte[16];if (null != mfc) {try {//连接NFCmfc.connect();//获取扇区数量int count = mfc.getSectorCount();//如果传进来的扇区大了或者小了直接退出方法if (a > count - 1 || a < 0) {callback.isSusses(false);return;}//获取写的扇区的块的数量int bCount = mfc.getBlockCountInSector(a);//如果输入的块大了或者小了也是直接退出if (b > bCount - 1 || b < 0) {callback.isSusses(false);return;}//将字符转换为字节数组,这样其实并不好,无法转换汉字,因为汉字转出来要占三个字节for (int i = 0; i < 16; i++) {if (i < str.length()) {data[i] = (byte) str.charAt(i);} else {data[i] = (byte) ' ';}}//验证扇区密码 bytes也是默认密码boolean isOpen = mfc.authenticateSectorWithKeyA(a, bytes);if (isOpen) {int bIndex = mfc.sectorToBlock(a);//写卡mfc.writeBlock(bIndex + b, data);}callback.isSusses(true);} catch (Exception e) {e.printStackTrace();callback.isSusses(false);} finally {try {mfc.close();} catch (IOException e) {e.printStackTrace();}}}

接下来说如何设置密码,其实跟写数据是一样的,只是需要将格式设置一下然后写到特定的地方而已

     Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);MifareClassic mfc = MifareClassic.get(tag);byte[] data = new byte[16];if (null != mfc) {try {mfc.connect();if (password.length() != PASSWORD_LENTH) {callback.isSusses(false);return;}int count = mfc.getSectorCount();if (a > count - 1 || a < 0) {callback.isSusses(false);return;}//将密码转换为keyAfor (int i = 0; i < password.length(); i++) {data[i] = (byte) password.charAt(i);}//将密码转换为KeyB 我AB密码一样的,也可以不一样for (int i = 0; i < password.length(); i++) {data[i + password.length() + 4] = (byte) password.charAt(i);}//输入控制位data[password.length()] = (byte) 0xff;data[password.length() + 1] = (byte) 0x07;data[password.length() + 2] = (byte) 0x80;data[password.length() + 3] = (byte) 0x69;//验证密码boolean isOpen = mfc.authenticateSectorWithKeyA(a, bytes);if (isOpen) {int bIndex = mfc.sectorToBlock(a);int bCount = mfc.getBlockCountInSector(a);//写到扇区的最后一个块mfc.writeBlock(bIndex + bCount - 1, data);}callback.isSusses(true);} catch (Exception e) {e.printStackTrace();callback.isSusses(false);} finally {try {mfc.close();} catch (IOException e) {e.printStackTrace();}}}

好了,大概就是这样的,理解通这个了的话,S50芯片应该就没有问题了,到时候想存什么都可以了,数据大于扇区还可把两个扇区一起用啊,这样可玩性就多了。

最后我写了一个完成的demo,代码有点丑,但是功能能实现的,有兴趣的可以看看。
https://download.csdn.net/download/version1_0/10375350

Android针对IC卡读写的NFC开发相关推荐

  1. android关于IC卡读写及加密解密

    byte[] key = {(byte) 0xA0, (byte) 0xB7, (byte) 0xA5, (byte) 0xC5, (byte) 0x80, (byte) 0x88}; Tag tag ...

  2. 串口IC卡读写器IC-07开发程序包(简单易用)

    开发程序包下载http://icmcu.com/download/2009-2-7/ChuanKou-IC-KaDouXieQi-IC-07-KaiFaBao.html

  3. IC-14W网络IC卡读写器_银河麒麟桌面操作系统V10适配测试报告

    银河麒麟操作系统产品NeoCertify 认证测试报告 系统版本:银河麒麟桌面操作系统V10 厂商名称:广州荣士电子有限公司 认证产品:IC-14W网络IC卡读写器 测试日期:2022-11-04 麒 ...

  4. java做的web系统 m1 读卡器 结合_IE浏览器接入IC卡读写器实现M1卡的读写功能

    基于ActiveX技术的ocx控件是实现网页上读写 IC卡的一个比较不错的方法,因为ocx是com组件,通过其发布的接口,IE可以实现所有的功能.ActiveX不仅能适应大部分编程语言,做到与编程语言 ...

  5. 关于IC卡读写器的应用

    IC卡读写器的应用领域 IC卡具有存储容量大,保密性好,体积小,便于携带的性能特点,可以广泛应用于门禁管理.会议签到.车辆管理.一卡通.身份验证识别等相关行业.本文介绍了一种基于射频识别技术的RFID ...

  6. Windows操作系统下用vmware虚拟ubuntu系统测试USB IC卡读写器的说明

    读写器介绍:RFID读写器NFC发卡器WEB可编程NDEF文本/网址/智能海报/电话/启动-淘宝网 (taobao.com) 一.打开windows计算机管理 / 服务 / VMware USB Ar ...

  7. IC卡读写器VB源代码

    IC卡读写器VB使用界面 详细代码 '广州荣士电子有限公司,联系电话020-82318861,82322852,定制13826029618 网址http://www.icmcu.com '读卡函数声明 ...

  8. 公交IC卡读写器设计指南

    采用PHILIPS公司的Mifaue卡作IC卡,设计以射频技术为核心,以单片机为控制器的IC卡读写器在公交自动收费系统中的应用.制作的IC卡读写器可以实现制卡.售卡.自动收费等功能,具有安全.实用.方 ...

  9. 单片机IC卡读取开题报告_基于单片机的ic卡读写系统的实现.doc

    基于单片机的ic卡读写系统的实现 2013届 分类号:TP311 单位代码:10452 毕业设计(论文) 基于单片机的IC卡读写系统的实现 姓 名 学 号 Abstract With the deve ...

最新文章

  1. Transformer 代码完全解读!
  2. 在蓄电池管理系统中计算机应用,汽车电器与电子技术.docx
  3. 第3周实践项目1 顺序表的基本运算
  4. MyBatis源码-深入理解MyBatis Executor的设计思想
  5. 微电网日前优化调度 。算例有代码(2)
  6. java list%3ca%3e排序_Apache Solr 远程命令+XXE执行漏洞(CVE-2017-12629)
  7. 第3章 Python 数字图像处理(DIP) - 灰度变换与空间滤波15 - 锐化高通滤波器 -拉普拉斯核(二阶导数)
  8. dfs.client.block.write.replace-datanode-on-failure
  9. 1 CentOS 6下FastDFS实现分布式文件系统
  10. JAVA 读取txt文件内容
  11. java------io基础(一)
  12. Delphi2010 Dll 函数列表查看
  13. java 两个图片相似度_JAVA比较两张图相似度
  14. 联邦贸易委员会:大数据带来的歧视风险
  15. flvplayer.swfnbsp;flv视频播放器…
  16. 口语语汇单词篇(7)
  17. windows 组策略
  18. Android Studio报错:E/EGL_emulation: tid 3197: eglSurfaceAttrib(1199): error 0x3009 (EGL_BAD_MATCH)
  19. python获取csv文件中某一列或者某些列
  20. hackbar2.1.3 安装教程(附下载地址 )Firefox Chrome

热门文章

  1. Ant Design Vue 相关介绍
  2. 教资计算机报高中害死初中,教师资格证报名入口必须电脑登录吗_中小学教师资格考试网...
  3. 高博SLAM基础课第四讲——非线性优化
  4. 怎样让宝贝从小做一个有道德的人?
  5. 论iOS开发与Android开发的前景与薪资水平
  6. 如何翻译DeepFaceLab(DeepFake)的交互式合成器
  7. 一款公历转农历节气以及天干地支的js代码
  8. 41.Django快速上手
  9. jt2go嵌入html控件,JT2Go(JT文件阅读器) 免费版v11.2
  10. 怎样阅读论文(台湾彭明辉)ZT