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;
    }

}
```

 

posted @ 2018-01-27 23:57  jiftle  阅读(5026)  评论(1编辑  收藏  举报