Android支持的数据格式
数据格式的Intent filter
AndroidManifest.xml文件中,要像向下列示例那样,在元素内的元素中指定你创建的资源文件:
<喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4KPHByZSBjbGFzcz0="brush:java;"> ... ...
nfc_tech_filter.xml文件(一个Tag标签只有全部匹配tech-list元素中的tech元素指定的nfc芯片时才认为被匹配):
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<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关系):
1
2
3
4
5
6
7
|
<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>
|
1
2
3
4
5
6
|
<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>
|
1
2
3
4
5
6
7
8
9
10
11
|
<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()方法获取它所支持的所有标签类型,如果清单文件中所引用的资源文件中所有的中的芯片是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:
- 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. - When your application receives the intent, obtain the
Tag
object from the intent:1Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
- Obtain an instance of a
TagTechnology
, by calling one of theget
factory methods of the classes in theandroid.nfc.tech
package. You can enumerate the supported technologies of the tag by callinggetTechList()
before calling aget
factory method. For example, to obtain an instance ofMifareUltralight
from aTag
, do the following:1MifareUltralight.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.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253package
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
;
}
}
例子程序:
12345678910<!--?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"
>
</imageview></textview></checkbox></linearlayout>
MainActivity:123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207package
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
;
}
}
清单文件:12345678910111213141516<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"
>
<intent-filter>
<category android:name=
"android.intent.category.LAUNCHER"
>
</category></action></intent-filter>
</activity>
</application>
</uses-permission></uses-sdk></manifest>