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="&#xe779;"
			   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.运行效果图如下:

 

本人NFC扫描卡片功能就是参考模仿下面源码完成的。

详细请参考下载源码-->Android NFC读MifareClassic卡获取卡片ID类型

如果想研究Android NFC源码读取公交卡信息余额和交易记录的

请参考另一篇文章-->Android NFC源码读取公交卡信息余额和交易记录

猜你喜欢

转载自blog.csdn.net/qq_36135335/article/details/82495413