Android(安卓)NFC读MifareClassic卡获取卡片ID 类型 扇区 存储空间
1.首先要在AndroidManifest.xml中声明如下配置信息:
为了能够使用Android手机的NFC功能,需要在Manifest文件中添加相应的权限:
详细配置请参考-->Android NFC标签读写配置过滤器总结
2.NFC TAG的发布系统:
当android设备扫描到一个NFC标签时,会自动寻找最适合的Activity来处理这个TAG,如果有多个Activity满足条件的话,会让用户来选择到底使用哪一个Activity来处理,可以理解为就是简单的事件响应与事件处理。
那么如何让一个Activity监听 ”当扫描到NFC标签时” 的这一个事件呢?使用intent filter。
可以理解为当检测到一个NFC标签时,系统自动创建一个相关Intent对象,含有响应intent-filter的Activity将处理这个Intent。
其中,intent filter声明如下:(在AndroidManifest.xml中声明在你需要捕获这个Intent的Activity里)(如下是识别公交卡的TECH格式过滤标签)即ACTION_TECH_DISCOVERED类型的过滤器:
配置android:name=".NFCActivity"是为了当退出app时只要扫描卡片能直接打开app并定位到NFC扫描界面。
在res文件夹下新建一个xml的文件夹,里面放的是Android支持的NFC类型的配置数据。nfc_tech_filter.xml如下:
android.nfc.tech.IsoDep android.nfc.tech.NfcA android.nfc.tech.NfcB android.nfc.tech.NfcF android.nfc.tech.NfcV android.nfc.tech.Ndef android.nfc.tech.NdefFormatable android.nfc.tech.MifareUltralight android.nfc.tech.MifareClassic
另外还有ACTION_NDEF_DISCOVERED类型的过滤器
ACTION_TAG_DISCOVERED类型的过滤器
3.详细代码如下:
res/layout/nfc_info.xml
<?xml version="1.0" encoding="utf-8"?>
NFCActivity.java
import android.app.Activity;import android.app.PendingIntent;import android.content.Intent;import android.nfc.NfcAdapter;import android.nfc.Tag;import android.nfc.tech.MifareClassic;import android.os.Bundle;import android.view.View;import android.widget.TextView;import android.widget.Toast;public class NFCActivity extends Activity {NfcAdapter nfcAdapter;TextView promt;private PendingIntent pi;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.nfc_info);promt = (TextView) findViewById(R.id.promt);// 获取默认的NFC控制器nfcAdapter = NfcAdapter.getDefaultAdapter(this);pi = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);if (nfcAdapter == null) {Toast.makeText(this, "对不起,您的设备不支持nfc功能!", Toast.LENGTH_SHORT).show();//promt.setText("设备不支持NFC!");finish();return;}if (!nfcAdapter.isEnabled()) {Toast.makeText(this, "请在系统设置中开启NFC功能!", Toast.LENGTH_SHORT).show();//promt.setText("请在系统设置中先启用NFC功能!");finish();return;}}public void btn_back(View view){this.finish();}@Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); // 当前app正在前端界面运行,这个时候有intent发送过来,那么系统就会调用onNewIntent回调方法,将intent传送过来 // 我们只需要在这里检验这个intent是否是NFC相关的intent,如果是,就调用处理方法 if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) { processIntent(intent); } } //页面获取焦点 @Override protected void onResume() { super.onResume(); nfcAdapter.enableForegroundDispatch(this, pi, null, null); }//页面失去焦点 @Override protected void onPause() { super.onPause(); if(nfcAdapter!=null){ nfcAdapter.disableForegroundDispatch(this);//关闭前台发布系统 } }/*@Overrideprotected void onResume() {super.onResume();//得到是否检测到ACTION_TECH_DISCOVERED触发if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(getIntent().getAction())) {//处理该intentprocessIntent(getIntent());}}*///字符序列转换为16进制字符串private String bytesToHexString(byte[] src) {StringBuilder stringBuilder = new StringBuilder("0x");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();}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; }/** * Parses the NDEF Message from the intent and prints to the TextView */private void processIntent(Intent intent) {//取出封装在intent中的TAGTag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);String CardId =ByteArrayToHexString(tagFromIntent.getId());String metaInfo = "";metaInfo+="卡片ID:"+CardId;for (String tech : tagFromIntent.getTechList()) {System.out.println(tech);}boolean auth = false;//读取TAGMifareClassic mfc = MifareClassic.get(tagFromIntent);try {//Enable I/O operations to the tag from this TagTechnology object.mfc.connect();int type = mfc.getType();//获取TAG的类型int sectorCount = mfc.getSectorCount();//获取TAG中包含的扇区数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 += "\n卡片类型:" + typeS + "\n共" + sectorCount + "个扇区\n共"+ mfc.getBlockCount() + "个块\n存储空间: " + mfc.getSize() + "B\n";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 + ":验证成功\n";// 读取扇区中的块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 + ":验证失败\n";}}promt.setText(metaInfo);//Toast.makeText(this, metaInfo, Toast.LENGTH_SHORT).show();} catch (Exception e) {e.printStackTrace();}}}
4.运行效果图如下:
本人NFC扫描卡片功能就是参考模仿下面源码完成的。
详细请参考下载源码Eclipse版本-->Android NFC读MifareClassic卡获取卡片ID类型
如果想研究Android NFC源码读取公交卡信息余额和交易记录的
请参考另一篇文章-->Android NFC源码读取公交卡信息余额和交易记录
更多相关文章
- Android中Java根据文件头获取文件类型的方法
- Android配置build.gradle的buildTypes动态自动维护debug和releas
- android videoView 按不同比例缩放
- Android系统使用MediaFile类判断音频文件类型
- RxJava用法简单整理(Android)
- Android使用me.dm7.barcodescanner:zxing扫描二维码乱码问题处理
- ANDROID JNI的使用简介
- BLE 扫描及连接 android程序开发(一)
- Android(安卓)NDK数据类型转换详解