日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

android nfc ndef mifareclassic,Android NFC开发-实践篇

發(fā)布時(shí)間:2025/3/12 Android 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android nfc ndef mifareclassic,Android NFC开发-实践篇 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Android NFC開(kāi)發(fā)-實(shí)踐篇

https://blog..net/_GYG/article/details/72899417

在Android NFC開(kāi)發(fā)-理論篇中,我們了解了在Android中開(kāi)發(fā)NFC的一些理論知識(shí),這篇我們繼續(xù)應(yīng)用我們上一篇學(xué)到的知識(shí),實(shí)現(xiàn)對(duì)NDEF格式標(biāo)簽和MifareClassic格式標(biāo)簽的讀寫(xiě)操作。

基本操作

配置AndroidMenifest.xml:

獲取設(shè)備默認(rèn)的NfcAdapter對(duì)象,判斷該設(shè)備是否支持NFC功能,若支持,判斷此功能是否打開(kāi),并且創(chuàng)建一個(gè)PendingIntent對(duì)象,用于當(dāng)NFC標(biāo)簽被檢測(cè)到時(shí),啟動(dòng)我們處理NFC標(biāo)簽的Activity

@Override

protected void onStart() {

super.onStart();

mNfcAdapter= NfcAdapter.getDefaultAdapter(this);//設(shè)備的NfcAdapter對(duì)象

if(mNfcAdapter==null){//判斷設(shè)備是否支持NFC功能

Toast.makeText(this,"設(shè)備不支持NFC功能!",Toast.LENGTH_SHORT);

finish();

return;

}

if (!mNfcAdapter.isEnabled()){//判斷設(shè)備N(xiāo)FC功能是否打開(kāi)

Toast.makeText(this,"請(qǐng)到系統(tǒng)設(shè)置中打開(kāi)NFC功能!",Toast.LENGTH_SHORT);

finish();

return;

}

mPendingIntent=PendingIntent.getActivity(this,0,new Intent(this,getClass()),0);//創(chuàng)建PendingIntent對(duì)象,當(dāng)檢測(cè)到一個(gè)Tag標(biāo)簽就會(huì)執(zhí)行此Intent

}

在OnNewIntent()方法中,獲取到Tag對(duì)象

@Override

protected void onNewIntent(Intent intent) {

super.onNewIntent(intent);

mTag=intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);//獲取到Tag標(biāo)簽對(duì)象

String[] techList=mTag.getTechList();

System.out.println("標(biāo)簽支持的tachnology類(lèi)型:");

for (String tech:techList){

System.out.println(tech);

}

}

為了更好的處理NFC標(biāo)簽,我們需要在Activity獲取焦點(diǎn)時(shí)(onResume),在主線程中啟動(dòng)前臺(tái)發(fā)布系統(tǒng),并且在Activity失去焦點(diǎn)時(shí),關(guān)閉前臺(tái)發(fā)布系統(tǒng)

//頁(yè)面獲取焦點(diǎn)

@Override

protected void onResume() {

super.onResume();

if (mNfcAdapter!=null){ mNfcAdapter.enableForegroundDispatch(this,mPendingIntent,null,null);//打開(kāi)前臺(tái)發(fā)布系統(tǒng),使頁(yè)面優(yōu)于其它nfc處理.當(dāng)檢測(cè)到一個(gè)Tag標(biāo)簽就會(huì)執(zhí)行mPendingItent

}

}

//頁(yè)面失去焦點(diǎn)

@Override

protected void onPause() {

super.onPause();

if(mNfcAdapter!=null){

mNfcAdapter.disableForegroundDispatch(this);//關(guān)閉前臺(tái)發(fā)布系統(tǒng)

}

}

以上所有操作,都是對(duì)一個(gè)NFC標(biāo)簽的基本操作,我們封裝在一個(gè)BaseNfcActivity中,對(duì)不同格式標(biāo)簽讀寫(xiě)的Activity都繼承BaseNfcActivity。

NDEF格式標(biāo)簽讀寫(xiě)

我們可以通過(guò)Tag對(duì)象的getTechList()獲取到標(biāo)簽的技術(shù)類(lèi)型,只有支持NDEF格式的標(biāo)簽才可以進(jìn)行NDEF格式標(biāo)簽的讀寫(xiě)操作。

讀寫(xiě)NDEF格式標(biāo)簽主要涉及到兩個(gè)類(lèi):

NdefMessage:描述NDEF格式的信息,實(shí)際上我們寫(xiě)入NFC標(biāo)簽的就是NdefMessage對(duì)象。

NdefRecord:描述NDEF信息的一個(gè)信息段,一個(gè)NdefMessage可能包含一個(gè)或者多個(gè)NdefRecord。

獲取Ndef對(duì)象

Ndef ndef=Ndef.get(mTag);//獲取ndef對(duì)象

創(chuàng)建NdefRecord,Android為我們提供了創(chuàng)建NdefRecord的方法,是我們可以輕松創(chuàng)建一個(gè)NdefRecord對(duì)象

NdefRecord.createApplicationRecord(String packageName)

NdefRecord.createUri(Uri uri)

NdefRecord.createUri(String uriString)

NdefRecord.createTextRecord(String languageCode, String text)

遺憾的是NdefRecord.createTextRecord(String languageCode, String text)最小兼容sdk版本是21,對(duì)于需要兼容更小版本的應(yīng)用來(lái)說(shuō)就需要我們自己來(lái)實(shí)現(xiàn)這個(gè)方法。

不管什么格式的數(shù)據(jù)本質(zhì)上都是由一些字節(jié)組成的。對(duì)于NDEF文本格式來(lái)說(shuō),這些數(shù)據(jù)的第1個(gè)字節(jié)描述了數(shù)據(jù)的狀態(tài),然后若干個(gè)字節(jié)描述文本的語(yǔ)言編碼,最后剩余字節(jié)表示文本數(shù)據(jù)。這些數(shù)據(jù)格式由NFC Forum的相關(guān)規(guī)范定義,可以通過(guò)?http://members.nfc-forum.org/specs/spec_dashboard?下載相關(guān)的規(guī)范。

NDEF的文本數(shù)據(jù)規(guī)范:

偏移量

長(zhǎng)度(bytes)

描述

0

1

狀態(tài)字節(jié),見(jiàn)下表(狀態(tài)字節(jié)編碼格式)

1

n

ISO/IANA語(yǔ)言編碼。例如”en-US”,”fr-CA”。編碼格式是US-ASCII,長(zhǎng)度(n)由狀態(tài)字節(jié)的后6位指定。

n+1

m

文本數(shù)據(jù)。編碼格式是UTF-8或UTF-16。編碼格式由狀態(tài)字節(jié)的前3位指定。

狀態(tài)字節(jié)編碼格式:

字節(jié)位(0是最低位,7是最高位)

含義

7

0:文本編碼為UTF-8,1:文本編碼為UTF-16

6

必須設(shè)為0

5..0

語(yǔ)言編碼的長(zhǎng)度(占用的字節(jié)個(gè)數(shù))

創(chuàng)建文本NdefRecord

/**

* 創(chuàng)建NDEF文本數(shù)據(jù)

* @param text

* @return

*/

public static NdefRecord createTextRecord(String text) {

byte[] langBytes = Locale.CHINA.getLanguage().getBytes(Charset.forName("US-ASCII"));

Charset utfEncoding = Charset.forName("UTF-8");

//將文本轉(zhuǎn)換為UTF-8格式

byte[] textBytes = text.getBytes(utfEncoding);

//設(shè)置狀態(tài)字節(jié)編碼最高位數(shù)為0

int utfBit = 0;

//定義狀態(tài)字節(jié)

char status = (char) (utfBit + langBytes.length);

byte[] data = new byte[1 + langBytes.length + textBytes.length];

//設(shè)置第一個(gè)狀態(tài)字節(jié),先將狀態(tài)碼轉(zhuǎn)換成字節(jié)

data[0] = (byte) status;

//設(shè)置語(yǔ)言編碼,使用數(shù)組拷貝方法,從0開(kāi)始拷貝到data中,拷貝到data的1到langBytes.length的位置

System.arraycopy(langBytes, 0, data, 1, langBytes.length);

//設(shè)置文本字節(jié),使用數(shù)組拷貝方法,從0開(kāi)始拷貝到data中,拷貝到data的1 + langBytes.length

//到textBytes.length的位置

System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length);

//通過(guò)字節(jié)傳入NdefRecord對(duì)象

//NdefRecord.RTD_TEXT:傳入類(lèi)型 讀寫(xiě)

NdefRecord ndefRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,

NdefRecord.RTD_TEXT, new byte[0], data);

return ndefRecord;

}

創(chuàng)建NdefMessage,并且寫(xiě)入Ndef標(biāo)簽

//往Ndef標(biāo)簽中寫(xiě)數(shù)據(jù)

private void writeNdef(){

if (mTag==null){

Toast.makeText(this,"不能識(shí)別的標(biāo)簽類(lèi)型!",Toast.LENGTH_SHORT);

finish();

return;

}

Ndef ndef=Ndef.get(mTag);//獲取ndef對(duì)象

if (!ndef.isWritable()){

Toast.makeText(this,"該標(biāo)簽不能寫(xiě)入數(shù)據(jù)!",Toast.LENGTH_SHORT);

return;

}

NdefRecord ndefRecord=createTextRecord(writeEdt.getText().toString());//創(chuàng)建一個(gè)NdefRecord對(duì)象

NdefMessage ndefMessage=new NdefMessage(new NdefRecord[]{ndefRecord});//根據(jù)NdefRecord數(shù)組,創(chuàng)建一個(gè)NdefMessage對(duì)象

int size=ndefMessage.getByteArrayLength();

if (ndef.getMaxSize()

Toast.makeText(this,"標(biāo)簽容量不足!",Toast.LENGTH_SHORT);

return;

}

try {

ndef.connect();//連接

ndef.writeNdefMessage(ndefMessage);//寫(xiě)數(shù)據(jù)

Toast.makeText(this,"數(shù)據(jù)寫(xiě)入成功!",Toast.LENGTH_SHORT);

} catch (IOException e) {

e.printStackTrace();

} catch (FormatException e) {

e.printStackTrace();

}finally {

try {

ndef.close();//關(guān)閉連接

} catch (IOException e) {

e.printStackTrace();

}

}

}

讀Ndef文本數(shù)據(jù)

//讀取Ndef標(biāo)簽中數(shù)據(jù)

private void readNdef(){

if (mTag==null){

Toast.makeText(this,"不能識(shí)別的標(biāo)簽類(lèi)型!",Toast.LENGTH_SHORT);

finish();

return;

}

Ndef ndef=Ndef.get(mTag);//獲取ndef對(duì)象

try {

ndef.connect();//連接

NdefMessage ndefMessage=ndef.getNdefMessage();//獲取NdefMessage對(duì)象

if (ndefMessage!=null) readEdt.setText(parseTextRecord(ndefMessage.getRecords()[0]));

Toast.makeText(this,"數(shù)據(jù)讀取成功!",Toast.LENGTH_SHORT);

} catch (IOException e) {

e.printStackTrace();

} catch (FormatException e) {

e.printStackTrace();

}finally {

try {

ndef.close();//關(guān)閉鏈接

} catch (IOException e) {

e.printStackTrace();

}

}

}

/**

* 解析NDEF文本數(shù)據(jù),從第三個(gè)字節(jié)開(kāi)始,后面的文本數(shù)據(jù)

* @param ndefRecord

* @return

*/

public static String parseTextRecord(NdefRecord ndefRecord) {

/**

* 判斷數(shù)據(jù)是否為NDEF格式

*/

//判斷TNF

if (ndefRecord.getTnf() != NdefRecord.TNF_WELL_KNOWN) {

return null;

}

//判斷可變的長(zhǎng)度的類(lèi)型

if (!Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) {

return null;

}

try {

//獲得字節(jié)數(shù)組,然后進(jìn)行分析

byte[] payload = ndefRecord.getPayload();

//下面開(kāi)始NDEF文本數(shù)據(jù)第一個(gè)字節(jié),狀態(tài)字節(jié)

//判斷文本是基于UTF-8還是UTF-16的,取第一個(gè)字節(jié)"位與"上16進(jìn)制的80,16進(jìn)制的80也就是最高位是1,

//其他位都是0,所以進(jìn)行"位與"運(yùn)算后就會(huì)保留最高位

String textEncoding = ((payload[0] & 0x80) == 0) ? "UTF-8" : "UTF-16";

//3f最高兩位是0,第六位是1,所以進(jìn)行"位與"運(yùn)算后獲得第六位

int languageCodeLength = payload[0] & 0x3f;

//下面開(kāi)始NDEF文本數(shù)據(jù)第二個(gè)字節(jié),語(yǔ)言編碼

//獲得語(yǔ)言編碼

String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");

//下面開(kāi)始NDEF文本數(shù)據(jù)后面的字節(jié),解析出文本

String textRecord = new String(payload, languageCodeLength + 1,

payload.length - languageCodeLength - 1, textEncoding);

return textRecord;

} catch (Exception e) {

throw new IllegalArgumentException();

}

}

MifareClassic格式標(biāo)簽讀寫(xiě)

MifareClassic格式標(biāo)簽數(shù)據(jù)結(jié)構(gòu)

第一扇區(qū)的第一塊一般用于制造商占用塊

0-15個(gè)扇區(qū):一個(gè)扇區(qū)對(duì)應(yīng)4個(gè)塊,所以總共有64個(gè)塊,序號(hào)分別為0-63,第一個(gè)扇區(qū)對(duì)應(yīng):0-3塊,第二個(gè)扇區(qū)對(duì)應(yīng):4-7塊…

每個(gè)扇區(qū)的最后一個(gè)塊用來(lái)存放密碼或控制位,其余為數(shù)據(jù)塊,一個(gè)塊占用16個(gè)字節(jié),keyA占用6字節(jié),控制位占用4字節(jié),keyB占用6字節(jié)。

MifareClassic標(biāo)簽讀寫(xiě)常用api:

get():根據(jù)Tag對(duì)象來(lái)獲得MifareClassic對(duì)象;

Connect():允許對(duì)MifareClassic標(biāo)簽進(jìn)行IO操作;

getType():獲得MifareClassic標(biāo)簽的具體類(lèi)型:TYPE_CLASSIC,TYPE_PLUA,TYPE_PRO,TYPE_UNKNOWN;

getSectorCount():獲得標(biāo)簽總共有的扇區(qū)數(shù)量;

getBlockCount():獲得標(biāo)簽總共有的的塊數(shù)量;

getSize():獲得標(biāo)簽的容量:SIZE_1K,SIZE_2K,SIZE_4K,SIZE_MINI

authenticateSectorWithKeyA(int SectorIndex,byte[] Key):驗(yàn)證當(dāng)前扇區(qū)的KeyA密碼,返回值為ture或false。 常用KeyA:默認(rèn)出廠密碼:KEY_DEFAULT,各種用途的供貨商必須配合該技術(shù)的MAD:KEY_MIFARE_APPLICATION_DIRECTORY

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

getBlockCountInSector(int):獲得當(dāng)前扇區(qū)的所包含塊的數(shù)量;

sectorToBlock(int):當(dāng)前扇區(qū)的第1塊的塊號(hào);

writeBlock(int,data):將數(shù)據(jù)data寫(xiě)入當(dāng)前塊;注意:data必須剛好是16Byte,末尾不能用0填充,應(yīng)該用空格

readBlock(int):讀取當(dāng)前塊的數(shù)據(jù)。

close():禁止對(duì)標(biāo)簽的IO操作,釋放資源。

寫(xiě)MifareClassic格式標(biāo)簽數(shù)據(jù)

//寫(xiě)塊

private void writeBlock(){

if (mTag==null){

Toast.makeText(this,"無(wú)法識(shí)別的標(biāo)簽!",Toast.LENGTH_SHORT);

finish();

return;

}

if (!haveMifareClissic){

Toast.makeText(this,"不支持MifareClassic",Toast.LENGTH_SHORT);

finish();

return;

}

MifareClassic mfc=MifareClassic.get(mTag);

try {

mfc.connect();//打開(kāi)連接

boolean auth;

int sector=Integer.parseInt(sectorNum.getText().toString().trim());//寫(xiě)入的扇區(qū)

int block=Integer.parseInt(blockNum.getText().toString().trim());//寫(xiě)入的塊區(qū)

auth=mfc.authenticateSectorWithKeyA(sector,MifareClassic.KEY_DEFAULT);//keyA驗(yàn)證扇區(qū)

if (auth){

mfc.writeBlock(block,"0123456789012345".getBytes());//寫(xiě)入數(shù)據(jù)

Toast.makeText(this,"寫(xiě)入成功!",Toast.LENGTH_SHORT);

}

} catch (IOException e) {

e.printStackTrace();

}finally {

try {

mfc.close();//關(guān)閉連接

} catch (IOException e) {

e.printStackTrace();

}

}

}

讀MifareClassic格式標(biāo)簽數(shù)據(jù)

//讀取塊

private void readBlock(){

if (mTag==null){

Toast.makeText(this,"無(wú)法識(shí)別的標(biāo)簽!",Toast.LENGTH_SHORT);

finish();

return;

}

if (!haveMifareClissic){

Toast.makeText(this,"不支持MifareClassic",Toast.LENGTH_SHORT);

finish();

return;

}

MifareClassic mfc=MifareClassic.get(mTag);

try {

mfc.connect();//打開(kāi)連接

boolean auth;

int sector=Integer.parseInt(sectorNum.getText().toString().trim());//寫(xiě)入的扇區(qū)

int block=Integer.parseInt(blockNum.getText().toString().trim());//寫(xiě)入的塊區(qū)

auth=mfc.authenticateSectorWithKeyA(sector,MifareClassic.KEY_DEFAULT);//keyA驗(yàn)證扇區(qū)

if (auth){

readData.setText(bytesToHexString(mfc.readBlock(block)));

}

} catch (IOException e) {

e.printStackTrace();

}finally {

try {

mfc.close();//關(guān)閉連接

} catch (IOException e) {

e.printStackTrace();

}

}

}

//字符序列轉(zhuǎn)換為16進(jìn)制字符串

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

}

總結(jié)

以上是生活随笔為你收集整理的android nfc ndef mifareclassic,Android NFC开发-实践篇的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。