Android NFC读MifareClassic卡获取卡片ID 类型 扇区 存储空间

1.首先要在AndroidManifest.xml中声明如下配置信息:

为了能够使用Android手机的NFC功能,需要在Manifest文件中添加相应的权限:

详细配置请参考-->Android NFC标签读写配置过滤器总结

    <uses-permission android:name="android.permission.NFC" />
    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="21" />
    <uses-feature android:name="android.hardware.nfc" android:required="true" />

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类型的过滤器:

    <activity android:name=".NFCActivity"  android:launchMode="singleInstance">
            <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>

配置android:name=".NFCActivity"是为了当退出app时只要扫描卡片能直接打开app并定位到NFC扫描界面。

在res文件夹下新建一个xml的文件夹,里面放的是Android支持的NFC类型的配置数据。nfc_tech_filter.xml如下:

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

另外还有ACTION_NDEF_DISCOVERED类型的过滤器

    <intent-filter>
                    <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                    <category android:name="android.intent.category.DEFAULT" />
                    <data android:mimeType="text/plain" />
    </intent-filter>

ACTION_TAG_DISCOVERED类型的过滤器

    <intent-filter>
           <action android:name="android.nfc.action.TAG_DISCOVERED"/>
           <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>

3.详细代码如下:

res/layout/nfc_info.xml

    <?xml version="1.0" encoding="utf-8"?>
    <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/app_background"
        >
    <LinearLayout 
        android:orientation="vertical" android:layout_width="match_parent"
        android:layout_height="wrap_content"
        >
      <AbsoluteLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginBottom="10dp"
            android:clickable="true"
            >
            <TextView 
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:padding="10dp"
                android:textSize="@dimen/enfore_title"
                android:textColor="@color/enfore_title"
                android:layout_x="0dp"
                android:layout_y="0dp"
                android:text="NFC测试"
                android:gravity="center"
                />
            <com.golden.test.iconfont.IconFontTextview     
                   android:layout_width="wrap_content"
                   android:layout_height="wrap_content"
                   android:textSize="@dimen/enfore_title"
                   android:textColor="@drawable/back_btn"
                   android:paddingTop="15dp"
                    android:paddingLeft="10dp"
                   android:text=""
                   android:clickable="true"
                   android:gravity="left|center_vertical"
                   android:layout_x="0dp"
                   android:layout_y="0dp"
                   android:onClick="btn_back"
                />
        </AbsoluteLayout>
      
          <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_margin="5dp"
              >
               <TextView 
                  android:id="@+id/promt"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:textColor="@color/enfore_title"
                  android:text="NFC扫描中..."
                  android:textSize="@dimen/app_info"
                  />
          </LinearLayout>
          
    </LinearLayout>
    </ScrollView>

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;
        @Override
        public 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);//关闭前台发布系统
                  }
           }
        /*@Override
        protected void onResume() {
            super.onResume();
            //得到是否检测到ACTION_TECH_DISCOVERED触发
            if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(getIntent().getAction())) {
                //处理该intent
                processIntent(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中的TAG
            Tag 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;
            //读取TAG
            MifareClassic 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.运行效果图如下:


image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容