http://www.2cto.com/kf/201404/296912.html
-
检测到标签后在Activity中的处理流程
1. 在onCreate()中获取NfcAdapter对象;
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
2.在onNewIntent()中获取Tag对象或者NdefMessage信息;
获取Tag对象:
Tag tag = intent.getParcelableExra(NfcAdapter.EXTRA_TAG);
获取NdefMessage信息:
Parcelable[] rawMsgs = getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
3.也可以通过Tag创建Ndef对象等,以实现标签的属性和I/O操作。
Ndef ndef = Ndef.get(tag);
NDEF格式标签的读取流程
1. 在onCreate()中获取NfcAdapter对象;
2.在onNewIntent()中判断是否为NDEF格式标签(ACTION_NDEF_DISCOVERED),若是则获取NdefMessage
信息;(需要强制转换成NdefMessage对象)
Parcelable[] rawMsgs = getIntent().getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES)
3.对NdefMessage对象进行解析,获取相关的文本信息或Uri等。
NDEF格式标签的写入流程
1. 在onCreate()中获取NfcAdapter对象;
2.在onNewIntent()中获取Tag对象;
Tag tag = intent.getParcelableExra(NfcAdapter.EXTRA_TAG);
3.通过Tag创建Ndef对象;
Ndef ndef = Ndef.get(tag);
4.将文本等数据封装成NdefMessage;
5.判断是否为NDEF格式标签,
若是NDEF格式:
(1)允许进行标签操作:ndef.connect();
(2) 调用ndef.writeNdefMessage(NdefMessage)方法写入。
若非NDEF格式:(1)NdefFromatable format = NdefFromatable.get();
(2)允许进行标签操作:format.connect();
(3)调用format.format(NdefMessage)方法写入。
NdefMessage信息结构
NdefRecZ喎�"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcmTW0LXEs6PTw7e9t6g8L3N0cm9uZz48YnI+CjwvcD4KPHA+MS6/yc2ouf1OZGVmUmVjb3JkLmdldFRuZigpt723qMC0u/G1w1RORtfWts6juzwvcD4KPHA+Mi7NqLn9TmRlZlJlY29yZC5nZXRUeXBlKCm3vbeowLS78bXDUlRE19a2zqOstbFUTkbOqlRORl9XRUxMX0tOT1dOyrG1xFJURKGjPC9wPgo8cD4zLs2ouf1OZGVmUmVjb3JkLmdldFBheWxvYWQoKbe9t6jAtLvxtcPKtbzKtsHQtLXEyv2+3aGjPC9wPgo8cD48YnI+CjwvcD4KPHA+PGJyPgo8L3A+CjxwPjxzdHJvbmc+TkRFRs7Esb4mIzI2Njg0O8q9PC9zdHJvbmc+PGJyPgo8L3A+CjxwPk5kZWZNZXNzYWdl1tC1xHBheWxhb2S+zcrHyrW8yrXEyv2+3aOsxuTW0E5ERUbOxLG+JiMyNjY4NDvKvc6qo7o8YnI+CjwvcD4KPHA+PGltZyBzcmM9"http://www.2cto.com/uploadfile/Collfiles/20140430/20140430090648250.png" alt="\">
NDEF Uri格式
1、NdefMessage中的paylaod就是实际的数据,其中NDEF文本格式为:
2、前缀需要查表解析
例子程序:
ReadWriteTextMainActivity:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169package
mobile.android.read.write.text;
import
java.nio.charset.Charset;
import
java.util.Locale;
import
android.app.Activity;
import
android.content.Intent;
import
android.nfc.NdefMessage;
import
android.nfc.NdefRecord;
import
android.nfc.NfcAdapter;
import
android.nfc.Tag;
import
android.nfc.tech.Ndef;
import
android.nfc.tech.NdefFormatable;
import
android.os.Bundle;
import
android.view.View;
import
android.widget.TextView;
import
android.widget.Toast;
public
class
ReadWriteTextMainActivity
extends
Activity {
private
TextView mInputText;
private
String mText;
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_read_write_text_main);
mInputText = (TextView) findViewById(R.id.textview_input_text);
}
//单击“输入要写入文本”按钮执行的方法
public
void
onClick_InputText(View view) {
Intent intent =
new
Intent(
this
, InputTextActivity.
class
);
//显示输入文本的界面
startActivityForResult(intent,
1
);
}
@Override
protected
void
onActivityResult(
int
requestCode,
int
resultCode, Intent data) {
if
(requestCode ==
1
&& resultCode ==
1
) {
//获取要写入标签的文本
mText = data.getStringExtra(
"text"
);
//在主界面显示要写入标签的文本
mInputText.setText(mText);
}
}
//当窗口的创建模式是singleTop或singleTask时调用,用于取代onCreate方法
//当NFC标签靠近手机,建立连接后调用
@Override
public
void
onNewIntent(Intent intent) {
//如果未设置要写入的文本,则读取标签上的文本数据
if
(mText ==
null
) {
Intent myIntent =
new
Intent(
this
, ShowNFCTagContentActivity.
class
);
//将intent传入另一个窗口,显示界面窗口
myIntent.putExtras(intent);
//需要指定这个Action,传递Intent对象时,Action不会传递
myIntent.setAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
startActivity(myIntent);
}
//将指定的文本写入NFC标签
else
{
//获取Tag对象
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
//创建NdefMessage对象和NdefRecord对象
NdefMessage ndefMessage =
new
NdefMessage(
new
NdefRecord[] {createTextRecord(mText)});
//开始向标签写入文本
if
(writeTag(ndefMessage, tag)) {
//如果成功写入文本,将mtext设为null
mText =
null
;
//将主窗口显示的要写入的文本清空,文本只能写入一次
//如要继续写入,需要再次指定新的文本,否则只会读取标签中的文本
mInputText.setText(
""
);
}
}
}
//创建一个封装要写入的文本的NdefRecord对象
public
NdefRecord createTextRecord(String text) {
//生成语言编码的字节数组,中文编码
byte
[] langBytes = Locale.CHINA.getLanguage().getBytes(
Charset.forName(
"US-ASCII"
));
//将要写入的文本以UTF_8格式进行编码
Charset utfEncoding = Charset.forName(
"UTF-8"
);
//由于已经确定文本的格式编码为UTF_8,所以直接将payload的第1个字节的第7位设为0
byte
[] textBytes = text.getBytes(utfEncoding);
int
utfBit =
0
;
//定义和初始化状态字节
char
status = (
char
) (utfBit + langBytes.length);
//创建存储payload的字节数组
byte
[] data =
new
byte
[
1
+ langBytes.length + textBytes.length];
//设置状态字节
data[
0
] = (
byte
) status;
//设置语言编码
System.arraycopy(langBytes,
0
, data,
1
, langBytes.length);
//设置实际要写入的文本
System.arraycopy(textBytes,
0
, data,
1
+ langBytes.length,
textBytes.length);
//根据前面设置的payload创建NdefRecord对象
NdefRecord record =
new
NdefRecord(NdefRecord.TNF_WELL_KNOWN,
NdefRecord.RTD_TEXT,
new
byte
[
0
], data);
return
record;
}
//将NdefMessage对象写入标签,成功写入返回ture,否则返回false
boolean
writeTag(NdefMessage message, Tag tag) {
int
size = message.toByteArray().length;
try
{
//获取Ndef对象
Ndef ndef = Ndef.get(tag);
if
(ndef !=
null
) {
//允许对标签进行IO操作
ndef.connect();
if
(!ndef.isWritable()) {
Toast.makeText(
this
,
"NFC Tag是只读的!"
, Toast.LENGTH_LONG)
.show();
return
false
;
}
if
(ndef.getMaxSize() < size) {
Toast.makeText(
this
,
"NFC Tag的空间不足!"
, Toast.LENGTH_LONG)
.show();
return
false
;
}
//向标签写入数据
ndef.writeNdefMessage(message);
Toast.makeText(
this
,
"已成功写入数据!"
, Toast.LENGTH_LONG).show();
return
true
;
}
else
{
//获取可以格式化和向标签写入数据NdefFormatable对象
NdefFormatable format = NdefFormatable.get(tag);
//向非NDEF格式或未格式化的标签写入NDEF格式数据
if
(format !=
null
) {
try
{
//允许对标签进行IO操作
format.connect();
format.format(message);
Toast.makeText(
this
,
"已成功写入数据!"
, Toast.LENGTH_LONG)
.show();
return
true
;
}
catch
(Exception e) {
Toast.makeText(
this
,
"写入NDEF格式数据失败!"
, Toast.LENGTH_LONG)
.show();
return
false
;
}
}
else
{
Toast.makeText(
this
,
"NFC标签不支持NDEF格式!"
, Toast.LENGTH_LONG)
.show();
return
false
;
}
}
}
catch
(Exception e) {
Toast.makeText(
this
, e.getMessage(), Toast.LENGTH_LONG).show();
return
false
;
}
}
}
InputTextActivity:
1234567891011121314151617181920212223242526package
mobile.android.read.write.text;
import
android.app.Activity;
import
android.content.Intent;
import
android.os.Bundle;
import
android.view.View;
import
android.widget.EditText;
public
class
InputTextActivity
extends
Activity {
private
EditText mTextTag;
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_input_text);
mTextTag = (EditText) findViewById(R.id.edittext_text_tag);
}
public
void
onClick_OK(View view) {
Intent intent =
new
Intent();
intent.putExtra(
"text"
, mTextTag.getText().toString());
setResult(
1
, intent);
finish();
}
}
ShowNFCTagContentActivity:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990package
mobile.android.read.write.text;
import
mobile.android.read.write.text.library.TextRecord;
import
android.app.Activity;
import
android.content.Intent;
import
android.nfc.NdefMessage;
import
android.nfc.NdefRecord;
import
android.nfc.NfcAdapter;
import
android.nfc.Tag;
import
android.nfc.tech.Ndef;
import
android.os.Bundle;
import
android.os.Parcelable;
import
android.widget.TextView;
import
android.widget.Toast;
public
class
ShowNFCTagContentActivity
extends
Activity {
private
TextView mTagContent;
private
Tag mDetectedTag;
private
String mTagText;
private
void
readAndShowData(Intent intent) {
mDetectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Ndef ndef = Ndef.get(mDetectedTag);
mTagText = ndef.getType() +
"\n最大数据容量:"
+ ndef.getMaxSize()
+
" bytes\n\n"
;
readNFCTag();
mTagContent.setText(mTagText);
}
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_nfctag_content);
mTagContent = (TextView) findViewById(R.id.textview_tag_content);
//获取Tag对象
mDetectedTag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);
//创建Ndef对象
Ndef ndef = Ndef.get(mDetectedTag);
//获取标签的类型和最大容量
mTagText = ndef.getType() +
"\n最大数据容量:"
+ ndef.getMaxSize()
+
" bytes\n\n"
;
//读取NFC标签的数据并解析
readNFCTag();
//将标签的相关信息显示在界面上
mTagContent.setText(mTagText);
}
private
void
readNFCTag() {
//判断是否为ACTION_NDEF_DISCOVERED
if
(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
//从标签读取数据(Parcelable对象)
Parcelable[] rawMsgs = getIntent().getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage msgs[] =
null
;
int
contentSize =
0
;
if
(rawMsgs !=
null
) {
msgs =
new
NdefMessage[rawMsgs.length];
//标签可能存储了多个NdefMessage对象,一般情况下只有一个NdefMessage对象
for
(
int
i =
0
; i < rawMsgs.length; i++) {
//转换成NdefMessage对象
msgs[i] = (NdefMessage) rawMsgs[i];
//计算数据的总长度
contentSize += msgs[i].toByteArray().length;
}
}
try
{
if
(msgs !=
null
) {
//程序中只考虑了1个NdefRecord对象,若是通用软件应该考虑所有的NdefRecord对象
NdefRecord record = msgs[
0
].getRecords()[
0
];
//分析第1个NdefRecorder,并创建TextRecord对象
TextRecord textRecord = TextRecord.parse(msgs[
0
]
.getRecords()[
0
]);
//获取实际的数据占用的大小,并显示在窗口上
mTagText += textRecord.getText() +
"\n\n纯文本\n"
+ contentSize +
" bytes"
;
}
}
catch
(Exception e) {
mTagContent.setText(e.getMessage());
}
}
}
}
TextRecord:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667package
mobile.android.read.write.text.library;
import
java.io.UnsupportedEncodingException;
import
java.util.Arrays;
import
android.nfc.NdefRecord;
public
class
TextRecord {
//存储解析出来的文本
private
final
String mText;
//不允许直接创建TextRecord对象,所以将构造方法声明为private
private
TextRecord(String text) {
mText = text;
}
//通过该方法可以获取解析出来的文本
public
String getText() {
return
mText;
}
// 将纯文本内容从NdefRecord对象(payload)中解析出来
public
static
TextRecord parse(NdefRecord record) {
//验证TNF是否为NdefRecord.TNF_WELL_KNOWN
if
(record.getTnf() != NdefRecord.TNF_WELL_KNOWN)
return
null
;
//验证可变长度类型是否为RTD_TEXT
if
(!Arrays.equals(record.getType(), NdefRecord.RTD_TEXT))
return
null
;
try
{
//获取payload
byte
[] payload = record.getPayload();
//下面代码分析payload:状态字节+ISO语言编码(ASCLL)+文本数据(UTF_8/UTF_16)
//其中payload[0]放置状态字节:如果bit7为0,文本数据以UTF_8格式编码,如果为1则以UTF_16编码
//bit6是保留位,默认为0
/*
* payload[0] contains the "Status Byte Encodings" field, per the
* NFC Forum "Text Record Type Definition" section 3.2.1.
*
* bit7 is the Text Encoding Field.
*
* if (Bit_7 == 0): The text is encoded in UTF-8 if (Bit_7 == 1):
* The text is encoded in UTF16
*
* Bit_6 is reserved for future use and must be set to zero.
*
* Bits 5 to 0 are the length of the IANA language code.
*/
String textEncoding = ((payload[
0
] &
0x80
) ==
0
) ?
"UTF-8"
:
"UTF-16"
;
//处理bit5-0。bit5-0表示语言编码长度(字节数)
int
languageCodeLength = payload[
0
] &
0x3f
;
//获取语言编码(从payload的第2个字节读取languageCodeLength个字节作为语言编码)
String languageCode =
new
String(payload,
1
, languageCodeLength,
"US-ASCII"
);
//解析出实际的文本数据
String text =
new
String(payload, languageCodeLength +
1
,
payload.length - languageCodeLength -
1
, textEncoding);
//创建一个TextRecord对象,并返回该对象
return
new
TextRecord(text);
}
catch
(UnsupportedEncodingException e) {
// should never happen unless we get a malformed tag.
throw
new
IllegalArgumentException(e);
}
}
}
AndroidManifest.xml:
12345678910111213141516171819202122<manifest android:versionname=
"1.0"
android:versioncode=
"1"
package
=
"mobile.android.read.write.text"
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<uses-sdk android:targetsdkversion=
"15"
android:minsdkversion=
"15"
>
<uses-permission android:name=
"android.permission.NFC"
>
<intent-filter>
<category android:name=
"android.intent.category.LAUNCHER"
>
</category>
<intent-filter>
<category android:name=
"android.intent.category.DEFAULT"
>
<data android:mimetype=
"text/plain"
>
</data>
</category>
</activity>
</activity></action></intent-filter></action></intent-filter></activity></application></uses-permission></uses-sdk></manifest>