Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android nfc中MifareClassic格式的讀寫

android nfc中MifareClassic格式的讀寫

編輯:關於Android編程

Android支持的數據格式

\


數據格式的Intent filter

AndroidManifest.xml文件中,要像向下列示例那樣,在元素內的元素中指定你創建的資源文件:

<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHByZSBjbGFzcz0="brush:java;"> ... ...

nfc_tech_filter.xml文件(一個Tag標簽只有全部匹配tech-list元素中的tech元素指定的nfc芯片時才認為被匹配):

	
		android.nfc.tech.IsoDep
		android.nfc.tech.NfcA
		android.nfc.tech.NfcB
		android.nfc.tech.NfcF
		android.nfc.tech.NfcV
		android.nfc.tech.Ndef
		android.nfc.tech.NdefFormatable
		android.nfc.tech.MifareClassic
		android.nfc.tech.MifareUltralight
	

也可創建多個資源文件(多個資源文件是OR關系,每個資源文件中的芯片是AND關系):


	
	android.nfc.tech.NfcA
	android.nfc.tech.Ndef
	android.nfc.tech.NdefFormatable
	


	
	android.nfc.tech.Ndef
	android.nfc.tech.NdefFormatable
	
或者在同一個資源文件中創建多個元素(多個元素之間是OR關系,元素中的是AND關系):

	
		android.nfc.tech.NfcA
	
	
		android.nfc.tech.NfcB
	
	
		android.nfc.tech.MifareClassic
	



查看標簽支持數據格式的方法:

通過Tag.getTechlist()方法,獲得標簽所支持的數據格式

通過Tag.getId()方法,獲得標簽的唯一ID標識

NfcAdapter == null:表示設備不支持NFC硬件

NfcAdapter.isEnable()方法:判斷NFC是否開啟


綜上所述:

一個Tag通過Tag.getTechlist()方法獲取它所支持的所有標簽類型,如果清單文件中所引用的資源文件中所有的中的芯片是Tag標簽所有支持標簽的子集則被匹配的,可以寫多個,每個時獨立的,只要有其中一個中的所有的中的芯片類型全部匹配Tag所支持的芯片則認為是匹配的。多個是OR關系,中的是AND關系。


MifareClassic標簽的外形結構

\


MifareClassic標簽的數據結構

\

注意事項(假設1k空間):

第一扇區的第一塊一般用於制造商占用塊

0-15個扇區:一個扇區對應4個塊,所以總共有64個塊,序號分別為0-63,第一個扇區對應:0-3塊,第二個扇區對應:4-7塊...

每個扇區的最後一個塊用來存放密碼或控制位,其余為數據塊,一個塊占用16個字節,keyA占用6字節,控制位占用4字節,keyB占用6字節


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


官方文檔:

Working with tag technologies and the ACTION_TECH_DISCOVERED intent

When a device scans a tag that has NDEF data on it, but could not be mapped to a MIME or URI, the tag dispatch system tries to start an activity with the ACTION_TECH_DISCOVERED intent. The ACTION_TECH_DISCOVERED is also used when a tag with non-NDEF data is scanned. Having this fallback allows you to work with the data on the tag directly if the tag dispatch system could not parse it for you. The basic steps when working with tag technologies are as follows:

  1. Filter for an ACTION_TECH_DISCOVERED intent specifying the tag technologies that you want to handle. SeeFiltering for NFC intents for more information. In general, the tag dispatch system tries to start aACTION_TECH_DISCOVERED intent when an NDEF message cannot be mapped to a MIME type or URI, or if the tag scanned did not contain NDEF data. For more information on how this is determined, see The Tag Dispatch System.
  2. When your application receives the intent, obtain the Tag object from the intent:
    Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
  3. Obtain an instance of a TagTechnology, by calling one of the get factory methods of the classes in theandroid.nfc.tech package. You can enumerate the supported technologies of the tag by callinggetTechList() before calling a get factory method. For example, to obtain an instance of MifareUltralightfrom a Tag, do the following:
    MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));

    Reading and writing to tags

    Reading and writing to an NFC tag involves obtaining the tag from the intent and opening communication with the tag. You must define your own protocol stack to read and write data to the tag. Keep in mind, however, that you can still read and write NDEF data when working directly with a tag. It is up to you how you want to structure things. The following example shows how to work with a MIFARE Ultralight tag.

    package com.example.android.nfc;
    
    import android.nfc.Tag;
    import android.nfc.tech.MifareUltralight;
    import android.util.Log;
    import java.io.IOException;
    import java.nio.charset.Charset;
    
    public class MifareUltralightTagTester {
    
        private static final String TAG = MifareUltralightTagTester.class.getSimpleName();
    
        public void writeTag(Tag tag, String tagText) {
            MifareUltralight ultralight = MifareUltralight.get(tag);
            try {
                ultralight.connect();
                ultralight.writePage(4, "abcd".getBytes(Charset.forName("US-ASCII")));
                ultralight.writePage(5, "efgh".getBytes(Charset.forName("US-ASCII")));
                ultralight.writePage(6, "ijkl".getBytes(Charset.forName("US-ASCII")));
                ultralight.writePage(7, "mnop".getBytes(Charset.forName("US-ASCII")));
            } catch (IOException e) {
                Log.e(TAG, "IOException while closing MifareUltralight...", e);
            } finally {
                try {
                    ultralight.close();
                } catch (IOException e) {
                    Log.e(TAG, "IOException while closing MifareUltralight...", e);
                }
            }
        }
    
        public String readTag(Tag tag) {
            MifareUltralight mifare = MifareUltralight.get(tag);
            try {
                mifare.connect();
                byte[] payload = mifare.readPages(4);
                return new String(payload, Charset.forName("US-ASCII"));
            } catch (IOException e) {
                Log.e(TAG, "IOException while writing MifareUltralight
                message...", e);
            } finally {
                if (mifare != null) {
                   try {
                       mifare.close();
                   }
                   catch (IOException e) {
                       Log.e(TAG, "Error closing tag...", e);
                   }
                }
            }
            return null;
        }
    }


    例子程序:

    
    
    
        
    
        
    
        
    
    

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

    清單文件:

    
    
        
    
        
    
        
            
                
                    
                    
                
            
        
    
    


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved