android nfc中MifareClassic格式的读写

来源:互联网 发布:cpda数据分析师考试 编辑:程序博客网 时间:2024/05/20 08:42


Android支持的数据格式


数据格式的Intent filter 

AndroidManifest.xml文件中,要像向下列示例那样,在<activity>元素内的<meta-data>元素中指定你创建的资源文件:

<activity>...  <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>
nfc_tech_filter.xml文件(一个Tag标签只有全部匹配tech-list元素中的tech元素指定的nfc芯片时才认为被匹配):
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">  <tech-list>    <tech>android.nfc.tech.IsoDep</tech>    <tech>android.nfc.tech.NfcA</tech>    <tech>android.nfc.tech.NfcB</tech>    <tech>android.nfc.tech.NfcF</tech>    <tech>android.nfc.tech.NfcV</tech>    <tech>android.nfc.tech.Ndef</tech>    <tech>android.nfc.tech.NdefFormatable</tech>    <tech>android.nfc.tech.MifareClassic</tech>    <tech>android.nfc.tech.MifareUltralight</tech>  </tech-list></resources>

也可创建多个资源文件(多个资源文件是OR关系,每个资源文件中的芯片是AND关系):

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">

<tech-list>  <tech>android.nfc.tech.NfcA</tech>  <tech>android.nfc.tech.Ndef</tech>  <tech>android.nfc.tech.NdefFormatable</tech>  </tech-list></resources>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">  <tech-list>  <tech>android.nfc.tech.Ndef</tech>  <tech>android.nfc.tech.NdefFormatable</tech>  </tech-list></resources>
或者在同一个资源文件中创建多个<tech-list>元素(多个<tech-list>元素之间是OR关系,<tech-list>元素中的<tech>是AND关系):
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">  <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.MifareClassic</tech>  </tech-list></resources>
查看标签支持数据格式的方法:

通过Tag.getTechlist()方法,获得标签所支持的数据格式

通过Tag.getId()方法,获得标签的唯一ID标识

NfcAdapter == null:表示设备不支持NFC硬件

NfcAdapter.isEnable()方法:判断NFC是否开启

综上所述:

一个Tag通过Tag.getTechlist()方法获取它所支持的所有标签类型,如果清单文件中所引用的<tech-list>资源文件中所有的<tech>中的芯片是Tag标签所有支持标签的子集则被匹配的,可以写多个<tech-list>,每个<tech-list>时独立的,只要有其中一个<tech-list>中的所有的<tech>中的芯片类型全部匹配Tag所支持的芯片则认为是匹配的。多个<tech-list>是OR关系,<tech-list>中的<tech>是AND关系。

MifareClassic标签的外形结构


MifareClassic标签的数据结构

MifareClassic类的常用方法

get():根据Tag对象来获得MifareClassic对象;

Connect():允许对MifareClassic标签进行IO操作;

getType():获得MifareClassic标签的具体类型:TYPE_CLASSIC,TYPE_PLUA,TYPE_PRO,TYPE_UNKNOWN;

getSectorCount():获得标签总共有的扇区数量;

getBlockCount():获得标签总共有的的块数量;

getSize():获得标签的容量:SIZE_1K,SIZE_2K,SIZE_4K,SIZE_MINI

authenticateSectorWithKeyA(int SectorIndex,byte[] Key):验证当前扇区的KeyA密码,返回值为ture或false。

常用KeyA:默认出厂密码:KEY_DEFAULT,

各种用途的供货商必须配合该技术的MAD:KEY_MIFARE_APPLICATION_DIRECTORY

被格式化成NDEF格式的密码:KEY_NFC_FORUM

getBlockCountInSector(int):获得当前扇区的所包含块的数量;

sectorToBlock(int):当前扇区的第1块的块号;

WriteBlock(int,data):将数据data写入当前块;

readBlock(int):读取当前块的数据。

close():禁止对标签的IO操作,释放资源。


MifareClassic标签的读写流程

获得Adapter对象

获得Tag对象

获得MifareClassic对象

读取数据块的数据

Connect(),readBlock(),close()  

获得Adapter对象

获得Tag对象

获得MifareClassic对象

将数据块写入标签

Connect(),writeBlock(),close() 

例子程序:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:orientation="vertical" >  <CheckBox    android:id="@+id/checkbox_write"    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:text="是否向NFC标签写入数据" />  <TextView    android:layout_width="match_parent"    android:layout_height="wrap_content"    android:layout_marginBottom="5dp"    android:text="请将NFC标签或贴纸靠近手机背面"    android:textSize="16sp" />  <ImageView    android:layout_width="match_parent"    android:layout_height="match_parent"    android:layout_margin="10dp"    android:src="@drawable/read_nfc_tag" /></LinearLayout>
MainActivity: 
package mobile.android.mifareultralight;import java.io.IOException;import java.nio.charset.Charset;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.util.Log;import android.widget.CheckBox;import android.widget.Toast;public class MifareultralightMainActivity extends Activity {  private CheckBox  mWriteData;  private NfcAdaptermNfcAdapter;  private PendingIntent mPendingIntent;  @Override  public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_mifareultralight);    mWriteData = (CheckBox) findViewById(R.id.checkbox_write);    mNfcAdapter = mNfcAdapter.getDefaultAdapter(this);    if (mNfcAdapter == null) {      Toast.makeText(this, "设备不支持NFC!", Toast.LENGTH_LONG).show();      finish();      return;    }    if (!mNfcAdapter.isEnabled()) {      Toast.makeText(this, "请在系统设置中先启用NFC功能!", Toast.LENGTH_LONG).show();      finish();      return;    }    mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,        getClass()), 0);  }  @Override  public void onResume() {    super.onResume();    if (mNfcAdapter != null)      mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null,          null);  }  @Override  public void onNewIntent(Intent intent) {    Tag tag = intent.getParcelableExtra(mNfcAdapter.EXTRA_TAG);    String[] techList = tag.getTechList();    boolean haveMifareUltralight = false;    for (String tech : techList) {      if (tech.indexOf("MifareClassic") >= 0) {        haveMifareUltralight = true;        break;      }    }    if (!haveMifareUltralight) {      Toast.makeText(this, "不支持MifareClassic", Toast.LENGTH_LONG).show();      return;    }    if (mWriteData.isChecked()) {      writeTag(tag);    } else {      String data = readTag(tag);      if (data != null) {        Log.i(data, "ouput");        Toast.makeText(this, data, Toast.LENGTH_LONG).show();      }    }  }  @Override  public void onPause() {    super.onPause();    if (mNfcAdapter != null)      mNfcAdapter.disableForegroundDispatch(this);  }  public void writeTag(Tag tag) {    MifareClassic mfc = MifareClassic.get(tag);    try {      mfc.connect();      boolean auth = false;      short sectorAddress = 1;      auth = mfc.authenticateSectorWithKeyA(sectorAddress,          MifareClassic.KEY_NFC_FORUM);      if (auth) {        // the last block of the sector is used for KeyA and KeyB cannot be overwritted        mfc.writeBlock(4, "1313838438000000".getBytes());        mfc.writeBlock(5, "1322676888000000".getBytes());        mfc.close();        Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show();      }    } catch (IOException e) {      // TODO Auto-generated catch block      e.printStackTrace();    } finally {      try {        mfc.close();      } catch (IOException e) {        // TODO Auto-generated catch block        e.printStackTrace();      }    }  }  //字符序列转换为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();  }  public String readTag(Tag tag) {    MifareClassic mfc = MifareClassic.get(tag);    for (String tech : tag.getTechList()) {      System.out.println(tech);    }    boolean auth = false;    //读取TAG    try {      String metaInfo = "";      //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 += "卡片类型:" + 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_NFC_FORUM);        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";        }      }      return metaInfo;    } catch (Exception e) {      Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();      e.printStackTrace();    } finally {      if (mfc != null) {        try {          mfc.close();        } catch (IOException e) {          Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG)              .show();        }      }    }    return null;  }}
清单文件: 
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  package="mobile.android.mifareultralight"  android:versionCode="1"  android:versionName="1.0" >  <uses-sdk    android:minSdkVersion="15"    android:targetSdkVersion="15" />  <uses-permission android:name="android.permission.NFC" />  <application    android:icon="@drawable/ic_launcher"    android:label="@string/app_name"    android:theme="@style/AppTheme" >    <activity      android:name=".MifareultralightMainActivity"      android:label="Mifareultralight"      android:launchMode="singleTop"      android:screenOrientation="portrait" >      <intent-filter>        <action android:name="android.intent.action.MAIN" />        <category android:name="android.intent.category.LAUNCHER" />      </intent-filter>    </activity>  </application></manifest>
0 0