NFC读卡APP
# 设计文档
### 简介
-----------------------------
这个APP的功能是使用手机的NFC读卡器功能,做到读取卡片
支持M1卡和CPU卡。
### 功能列表
-----------------------------
- 基本功能
- 读卡唯一号
- 读卡SAK(可以判断卡类型 08 M1卡 28 复合卡 20 CPU卡)
- Mifare卡操作
- 读取扇区信息
- CPU卡操作
- 选择MF(3F00)
- 取随机数
### 备注
-----------------------------
本来考虑到增加APP的功能,能够支持自己输入指令执行,但是考虑到
手机屏幕小,键盘输入不方便等,就不提供这些功能了。这个程序的
主要功能就是测试下基本的卡片的信息,足够用了。
工程代码下载地址: http://download.csdn.net/download/jiftlixu/10227604
```
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.yctxkj">
<uses-permission android:name="android.permission.NFC" />
<!-- 要求当前设备必须要有NFC芯片 -->
<!--<uses-feature android:name="android.hardware.nfc" android:required="true" />-->
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
```
MainActivity.java
```
package com.yctxkj;
import android.app.PendingIntent;
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.NfcA;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.app.AlertDialog;
import android.content.DialogInterface;
import java.io.IOException;
import java.util.ArrayList;
import java.lang.reflect.Array;
import java.util.List;
import android.widget.ArrayAdapter;
import android.app.ListActivity;
import android.app.ListActivity;
import android.view.View;
import android.content.Intent;
import com.yctxkj.mifare.MifareBlock;
import com.yctxkj.mifare.MifareClassCard;
import com.yctxkj.mifare.MifareSector;
import com.yctxkj.util.Converter;
import android.content.IntentFilter.MalformedMimeTypeException;
public class MainActivity extends AppCompatActivity {
//---------控件定义------------
Button btnSelectMF;
Button btnGetRand;
ListView listView;
Button btnReadCardSN;
Button btnCardSAK;
Button btnTechList;
Button btnReadMifareCard;
// NFC parts
private static NfcAdapter nfcAdapter;
private static PendingIntent mPendingIntent;
private static IntentFilter[] mFilters;
private static String[][] mTechLists;
private Intent mIntent = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//----------------控件---------------------
btnSelectMF = (Button) findViewById(R.id.btnSelectMF);
btnReadCardSN = (Button) findViewById(R.id.btnReadCardSN);
btnCardSAK = (Button) findViewById(R.id.btnCardSAK);
btnTechList = (Button) findViewById(R.id.btnTechList);
btnGetRand = (Button) findViewById(R.id.btnGetRand);
btnReadMifareCard = (Button) findViewById(R.id.btnReadMifareCard);
listView = (ListView) findViewById(R.id.listview_msg);
//-------------事件绑定---------------
btnSelectMF.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
SelectMF();
}
});
btnGetRand.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
GetRand();
}
});
btnReadCardSN.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ReadCardSN();
}
});
btnCardSAK.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
CardSAK();
}
});
btnTechList.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
TechList();
}
});
btnReadMifareCard.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ReadMifareCard();
}
});
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (nfcAdapter == null) {
Log.d("h_bl", "设备不支持NFC!");
Toast.makeText(getApplicationContext(), "设备不支持NFC!", Toast.LENGTH_SHORT).show();
return;
}
if (!nfcAdapter.isEnabled()) {
Toast.makeText(getApplicationContext(), "请在系统设置中先启用NFC功能!", Toast.LENGTH_SHORT).show();
Log.d("h_bl", "请在系统设置中先启用NFC功能!");
}
mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
getClass()), 0);
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
try {
ndef.addDataType("*/*");
} catch (MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
mFilters = new IntentFilter[]{ndef};
//设置
mTechLists = new String[][]{new String[]{IsoDep.class
.getName()}, new String[]{MifareClassic.class.getName()}};//MifareClassic
mIntent = this.getIntent();
}
/**
* 读M1卡
*/
private void ReadMifareCard() {
String action = mIntent.getAction();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {//当前的action
Tag tag = mIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
MifareClassic mifareClassic = MifareClassic.get(tag);
if(mifareClassic == null){
showAlert("不是Mifare卡");
return;
}
MifareClassCard mifareClassCard=null;
try {
mifareClassic.connect();
boolean auth = false;
// 5.2) and get the number of sectors this card has..and loop
// thru these sectors
int secCount = mifareClassic.getSectorCount();
mifareClassCard= new MifareClassCard(secCount);
int bCount = 0;
int bIndex = 0;
for (int j = 0; j < secCount; j++) {
MifareSector mifareSector = new MifareSector();
mifareSector.sectorIndex = j;
// 6.1) authenticate the sector
auth = mifareClassic.authenticateSectorWithKeyA(j,
MifareClassic.KEY_DEFAULT);
mifareSector.authorized = auth;
if (auth) {
// 6.2) In each sector - get the block count
bCount = mifareClassic.getBlockCountInSector(j);
bCount =Math.min(bCount, MifareSector.BLOCKCOUNT);
bIndex = mifareClassic.sectorToBlock(j);
for (int i = 0; i < bCount; i++) {
// 6.3) Read the block
byte []data = mifareClassic.readBlock(bIndex);
MifareBlock mifareBlock = new MifareBlock(data);
mifareBlock.blockIndex = bIndex;
// 7) Convert the data into a string from Hex
// format.
bIndex++;
mifareSector.blocks[i] = mifareBlock;
}
mifareClassCard.setSector(mifareSector.sectorIndex,
mifareSector);
} else { // Authentication failed - Handle it
}
}
ArrayList<String> blockData = new ArrayList<String>();
int blockIndex=0;
for(int i=0;i<secCount;i++){
MifareSector mifareSector=mifareClassCard.getSector(i);
for(int j=0;j<MifareSector.BLOCKCOUNT;j++){
MifareBlock mifareBlock=mifareSector.blocks[j];
byte []data=mifareBlock.getData();
blockData.add("Block "+ blockIndex++ +" : "+ Converter.getHexString(data, data.length));
}
}
//---------------------显示输出---------------------
String[] contents = new String[blockData.size()];
blockData.toArray(contents);
listView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, contents));
mifareClassic.close();
} catch (IOException e) {
// Log.e(TAG, e.getLocalizedMessage());
//showAlert(3);
}
} else {
showAlert("没有寻到卡片 00");
}
}
/**
* 选择MF
*/
private void SelectMF() {
String action = mIntent.getAction();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {
Tag tagFromIntent = mIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
IsoDep isoDep = IsoDep.get(tagFromIntent);
if(isoDep == null){
showAlert("不是CPU卡");
return;
}
try {
//连接卡片
isoDep.connect();
ArrayList<String> blockData = new ArrayList<String>();
byte[] sendData = null;
byte[] recvB = null;
String send = "";
String recv = "";
send = "00A40000023F00";
sendData = Converter.hexStringToByte(send);
recvB = isoDep.transceive(sendData);
recv = Converter.getHexString(recvB, recvB.length);
blockData.add(send);
blockData.add(">" + recv);
//断开卡片
isoDep.close();
//---------------------显示输出---------------------
String[] contents = new String[blockData.size()];
blockData.toArray(contents);
listView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, contents));
} catch (IOException e) {
// Log.e(TAG, e.getLocalizedMessage());
//showAlert(3);
}
} else {
showAlert("没有寻到卡片 00");
}
}
/**
* 取随机数
*/
private void GetRand() {
String action = mIntent.getAction();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {//当前的action
Tag tag = mIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
IsoDep isoDep = IsoDep.get(tag);
if(isoDep == null){
showAlert("不是CPU卡");
return;
}
try {
isoDep.connect();
if (isoDep.isConnected() == false) {
showAlert("连接卡片失败");
return;
}
byte[] sendData = null;
byte[] recvB = null;
String send = "";
String recv = "";
send = "0084000004";
sendData = Converter.hexStringToByte(send);
recvB = isoDep.transceive(sendData);
recv = Converter.getHexString(recvB, recvB.length);
ArrayList<String> blockData = new ArrayList<String>();
blockData.add(send);
blockData.add(">" + recv);
//---------------------显示输出---------------------
String[] contents = new String[blockData.size()];
blockData.toArray(contents);
listView.setAdapter(new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, contents));
isoDep.close();
} catch (IOException e) {
// Log.e(TAG, e.getLocalizedMessage());
//showAlert(3);
}
} else {
showAlert("没有寻到卡片 00");
}
}
/**
* 读卡唯一号
*/
private void ReadCardSN() {
String action = mIntent.getAction();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {//当前的action
Tag tag = mIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
byte[] bytCardSN = tag.getId();
String strCardSN = Converter.getHexString(bytCardSN, bytCardSN.length);
ArrayList<String> blockData = new ArrayList<String>();
blockData.add("读卡唯一号");
blockData.add(">" + strCardSN);
//---------------------显示输出---------------------
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("没有寻到卡片 00");
}
}
/**
* 支持的协议
*/
private void TechList() {
String action = mIntent.getAction();
ArrayList<String> blockData = new ArrayList<String>();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {//当前的action
Tag tag = mIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String[] arTeachList = tag.getTechList();
blockData.add("支持的协议");
for (int i = 0; i < arTeachList.length; i++) {
String strTeach = arTeachList[i];
blockData.add(">" + strTeach);
}
//---------------------显示输出---------------------
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("没有寻到卡片 00");
}
}
/**
* 读卡SAK
*/
private void CardSAK() {
String action = mIntent.getAction();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {//当前的action
Tag tag = mIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
NfcA nfcA = NfcA.get(tag);
byte[] bytAtqa = nfcA.getAtqa();
short Sak = nfcA.getSak();
int maxTranLen = nfcA.getMaxTransceiveLength();
String strAtqa = Converter.getHexString(bytAtqa, bytAtqa.length);
String strSAK = String.format("%02X", Sak);
String strCardType;
if (Sak == 0x08){
strCardType = "M1卡";
}else if(Sak == 0x20){
strCardType = "CPU卡";
}else if(Sak == 0x28 || Sak == 0x38){
strCardType = "复合卡";
}else{
strCardType = "未知类型";
}
ArrayList<String> blockData = new ArrayList<String>();
blockData.add("ATQA");
blockData.add(">" + strAtqa);
blockData.add("SAK");
blockData.add(">" + strSAK + " " + strCardType);
blockData.add("最大传输长度");
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("没有寻到卡片 00");
}
}
/**
* 显示对话框
*
* @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
public void onResume() {
super.onResume();
//-----------------非常关键,必要的哦,不能删除----------------
nfcAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters,
mTechLists);
}
@Override
public void onNewIntent(Intent intent) {
Log.i("Foreground dispatch", "Discovered tag with intent: " + intent);
//resolveIntent(intent);
// mText.setText("Discovered tag " + ++mCount + " with intent: " +
// intent);
mIntent = intent;
}
}
```
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
2017-01-27 在腾讯开发 QQ IM 的工作体验是怎样的?
2017-01-27 淘宝技术发展