https://blog.csdn.net/qilixiang012/article/details/24743791
检測到标签后在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信息结构
Supported TNFs and their mappings:
Type Name Format (TNF) | Mapping |
---|---|
TNF_ABSOLUTE_URI |
URI based on the type field. |
TNF_EMPTY |
Falls back to ACTION_TECH_DISCOVERED . |
TNF_EXTERNAL_TYPE |
URI based on the URN in the type field. The URN is encoded into the NDEF type field in a shortened form: <domain_name>:<service_name> . Android maps
this to a URI in the form: vnd.android.nfc://ext/<domain_name>:<service_name> . |
TNF_MIME_MEDIA |
MIME type based on the type field. |
TNF_UNCHANGED |
Invalid in the first record, so falls back to ACTION_TECH_DISCOVERED . |
TNF_UNKNOWN |
Falls back to ACTION_TECH_DISCOVERED . |
TNF_WELL_KNOWN |
MIME type or URI depending on the Record Type Definition (RTD), which you set in the type field. See Table 2. for more information on available RTDs and their mappings. |
Record Type Definition (RTD) | Mapping |
---|---|
RTD_ALTERNATIVE_CARRIER |
Falls back to ACTION_TECH_DISCOVERED . |
RTD_HANDOVER_CARRIER |
Falls back to ACTION_TECH_DISCOVERED . |
RTD_HANDOVER_REQUEST |
Falls back to ACTION_TECH_DISCOVERED . |
RTD_HANDOVER_SELECT |
Falls back to ACTION_TECH_DISCOVERED . |
RTD_SMART_POSTER |
URI based on parsing the payload. |
RTD_TEXT |
MIME type of text/plain . |
RTD_URI |
URI based on payload. |
说明:读取TNF的类型后(能够是上面第一张表中的类型),假设是TNF_WELL_KNOWN时。就能够获取RTD(相应格式良好的
{TNF_WELL_KNOWN}的标签的类型,能够是第二张表中的类型)
NdefRecord中的经常用法
1.可通过NdefRecord.getTnf()方法来获得TNF字段;
相应上图中Header中的Length
2.通过NdefRecord.getType()方法来获得RTD字段,当TNF为TNF_WELL_KNOWN时的RTD。
相应上图中Header中的Type
3.通过NdefRecord.getPayload()方法来获得实际读写的数据。
Header中的Identifier相应每个Record唯一的Id相应上图中的Payload
NDEF文本格式
NdefMessage中的paylaod就是实际的数据,当中NDEF文本格式为:
NDEF Uri格式
1、NdefMessage中的paylaod就是实际的数据,当中NDEF文本格式为:
2、前缀须要查表解析
Android应用程序记录Android Application Records(AAR)
1、在Android4.0中引入应用程序记录(AAR),当扫描到写入AAR的NFC标签时,启动相应的应用程序。
2、AAR有嵌入到NdefRecord内部的应用程序包名。Android会针对AAR来搜索整个NdefMessage,假设找到一个AAR,就会基于AAR内部的包名来启动应用程序。
3、NFC标签调度系统对包括AAR标签的调度:
1.若跟Intent匹配的Activity也跟AAR匹配,则启动该Activity。
2.若跟Intent匹配,而跟AAR不匹配。则启动AAR指定的应用程序;
3.假设没有跟AAR相应的应用程序,则启动各种市场来下载相应基于AAR的应用程序。
Android应用程序记录创建方法
1、调用NdefRecord类的creatApplicationRecord()方法来创建应用程序记录。
2、将所创建的AAR嵌入到NdefMessage中。
NdefMessage msg = new NdefMessage(new Ndefrecord[]{…,NdefRecord. creatApplicationRecord(“com.example.android.beam”)})
3、除非AAR是你NdefMessage中的唯一记录。否则不要将AAR嵌入到NdefMessage的第一条记录。
NDEF for Text 读写,样例程序:
ReadWriteTextMainActivity:
InputTextActivity:package 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); } //单击“输入要写入文本”button运行的方法 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; } } }
package 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:package 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() + "
最大数据容量:" + ndef.getMaxSize()
+ " bytes
";
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() + "
最大数据容量:" + ndef.getMaxSize()
+ " bytes
";
//读取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() + "
纯文本
"
+ contentSize + " bytes";
}
} catch (Exception e) {
mTagContent.setText(e.getMessage());
}
}
}
}
TextRecord:package 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:<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="mobile.android.read.write.text"
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=".ReadWriteTextMainActivity"
android:label="读写NFC标签的纯文本数据"
android:launchMode="singleTask" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity
android:name=".ShowNFCTagContentActivity"
android:label="显示NFC标签内容"
android:launchMode="singleTask" />
<activity
android:name=".InputTextActivity"
android:label="向NFC标签写入文本" />
</application>
</manifest>
NDEF for URL 读写,样例程序:
ReadWriteUriMainActivity:
UriListActivity:package mobile.android.read.write.uri; import mobile.android.read.write.uri.library.UriRecord; 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 ReadWriteUriMainActivity extends Activity { private TextView mSelectUri; private String mUri; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_read_write_uri_main); mSelectUri = (TextView) findViewById(R.id.textview_uri); } public void onClick_SelectUri(View view) { Intent intent = new Intent(this, UriListActivity.class); startActivityForResult(intent, 1); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == 1 && resultCode == 1) { mUri = data.getStringExtra("uri"); mSelectUri.setText(mUri); } } @Override public void onNewIntent(Intent intent) { if (mUri == null) { Intent myIntent = new Intent(this, ShowNFCTagContentActivity.class); myIntent.putExtras(intent); myIntent.setAction(NfcAdapter.ACTION_NDEF_DISCOVERED); startActivity(myIntent); } else { Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); NdefMessage ndefMessage = new NdefMessage( new NdefRecord[] {createUriRecord(mUri)}); if (writeTag(ndefMessage, tag)) { mUri = null; mSelectUri.setText(""); } } } public NdefRecord createUriRecord(String uriStr) { byte prefix = 0; //从uri前缀集合中找到匹配的前缀,并获得相应的标识代码 for (Byte b : UriRecord.URI_PREFIX_MAP.keySet()) { //将Uri前缀转换成小写 String prefixStr = UriRecord.URI_PREFIX_MAP.get(b).toLowerCase(); //前缀不为空串 if ("".equals(prefixStr)) continue; //比較Uri前缀 if (uriStr.toLowerCase().startsWith(prefixStr)) { //用字节表示的Uri前缀 prefix = b; //截取完整Uri中除了Uri前缀外的其它部分 uriStr = uriStr.substring(prefixStr.length()); break; } } //为存储在标签中的Uri创建一个Byte数组 byte[] data = new byte[1 + uriStr.length()]; //指定第1字节为Uri前缀的标识代码 data[0] = prefix; //将剩余的部分拷贝到data字节数组中 System.arraycopy(uriStr.getBytes(), 0, data, 1, uriStr.length()); //创建封装uri的NdefRecord对象 NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], data); //返回NdefRecord对象 return record; } boolean writeTag(NdefMessage message, Tag tag) { int size = message.toByteArray().length; try { Ndef ndef = Ndef.get(tag); if (ndef != null) { 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 format = NdefFormatable.get(tag); if (format != null) { try { 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; } } }
ShowNFCTagContentActivity:package mobile.android.read.write.uri; import android.app.ListActivity; import android.content.Intent; import android.graphics.Camera; import android.os.Bundle; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.SimpleAdapter; public class UriListActivity extends ListActivity implements OnItemClickListener { private String uris[] = new String[] {"http://www.google.com", "http://www.apple.com", "http://developer.apple.com", "http://www.126.com", "ftp://192.168.17.160", "https://192.168.17.120", "smb://192.168.17.100"}; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, uris); setListAdapter(arrayAdapter); getListView().setOnItemClickListener(this); } @Override public void onItemClick(AdapterView<?
> parent, View view, int position, long id) { Intent intent = new Intent(); intent.putExtra("uri", uris[position]); setResult(1, intent); finish(); } }
package mobile.android.read.write.uri;
import mobile.android.read.write.uri.library.UriRecord;
import android.app.Activity;
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;
public class ShowNFCTagContentActivity extends Activity {
private TextView mTagContent;
private Tag mDetectedTag;
private String 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);
mDetectedTag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);
Ndef ndef = Ndef.get(mDetectedTag);
mTagText = ndef.getType() + "
最大数据容量:" + ndef.getMaxSize()
+ " bytes
";
readNFCTag();
mTagContent.setText(mTagText);
}
private void readNFCTag() {
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
Parcelable[] rawMsgs = getIntent().getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage ndefMessage = null;
int contentSize = 0;
if (rawMsgs != null) {
if (rawMsgs.length > 0) {
ndefMessage = (NdefMessage) rawMsgs[0];
contentSize = ndefMessage.toByteArray().length;
} else {
return;
}
}
try {
NdefRecord record = ndefMessage.getRecords()[0];
UriRecord uriRecord = UriRecord
.parse(ndefMessage.getRecords()[0]);
mTagText += uriRecord.getUri().toString() + "
Uri
"
+ contentSize + " bytes";
} catch (Exception e) {
mTagContent.setText(e.getMessage());
}
}
}
}
UriRecord.javapackage mobile.android.read.write.uri.library;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import android.net.Uri;
import android.nfc.NdefRecord;
public class UriRecord {
//映射Uri前缀和相应的值
public static final Map<Byte, String> URI_PREFIX_MAP = new HashMap<Byte, String>();
static {
//设置NDEF Uri规范支持的Uri前缀。在解析payload时,须要依据payload的第1个字节定位相应的uri前缀
URI_PREFIX_MAP.put((byte) 0x00, "");
URI_PREFIX_MAP.put((byte) 0x01, "http://www.");
URI_PREFIX_MAP.put((byte) 0x02, "https://www.");
URI_PREFIX_MAP.put((byte) 0x03, "http://");
URI_PREFIX_MAP.put((byte) 0x04, "https://");
URI_PREFIX_MAP.put((byte) 0x05, "tel:");
URI_PREFIX_MAP.put((byte) 0x06, "mailto:");
URI_PREFIX_MAP.put((byte) 0x07, "ftp://anonymous:anonymous@");
URI_PREFIX_MAP.put((byte) 0x08, "ftp://ftp.");
URI_PREFIX_MAP.put((byte) 0x09, "ftps://");
URI_PREFIX_MAP.put((byte) 0x0A, "sftp://");
URI_PREFIX_MAP.put((byte) 0x0B, "smb://");
URI_PREFIX_MAP.put((byte) 0x0C, "nfs://");
URI_PREFIX_MAP.put((byte) 0x0D, "ftp://");
URI_PREFIX_MAP.put((byte) 0x0E, "dav://");
URI_PREFIX_MAP.put((byte) 0x0F, "news:");
URI_PREFIX_MAP.put((byte) 0x10, "telnet://");
URI_PREFIX_MAP.put((byte) 0x11, "imap:");
URI_PREFIX_MAP.put((byte) 0x12, "rtsp://");
URI_PREFIX_MAP.put((byte) 0x13, "urn:");
URI_PREFIX_MAP.put((byte) 0x14, "pop:");
URI_PREFIX_MAP.put((byte) 0x15, "sip:");
URI_PREFIX_MAP.put((byte) 0x16, "sips:");
URI_PREFIX_MAP.put((byte) 0x17, "tftp:");
URI_PREFIX_MAP.put((byte) 0x18, "btspp://");
URI_PREFIX_MAP.put((byte) 0x19, "btl2cap://");
URI_PREFIX_MAP.put((byte) 0x1A, "btgoep://");
URI_PREFIX_MAP.put((byte) 0x1B, "tcpobex://");
URI_PREFIX_MAP.put((byte) 0x1C, "irdaobex://");
URI_PREFIX_MAP.put((byte) 0x1D, "file://");
URI_PREFIX_MAP.put((byte) 0x1E, "urn:epc:id:");
URI_PREFIX_MAP.put((byte) 0x1F, "urn:epc:tag:");
URI_PREFIX_MAP.put((byte) 0x20, "urn:epc:pat:");
URI_PREFIX_MAP.put((byte) 0x21, "urn:epc:raw:");
URI_PREFIX_MAP.put((byte) 0x22, "urn:epc:");
URI_PREFIX_MAP.put((byte) 0x23, "urn:nfc:");
}
private final Uri mUri;
private UriRecord(Uri uri) {
this.mUri = uri;
}
//获取已经解析的Uri
public Uri getUri() {
return mUri;
}
public static UriRecord parse(NdefRecord record) {
//获取TNF
short tnf = record.getTnf();
//TNF是TNF_WELL_KNOWN,使用了前缀的Uri
if (tnf == NdefRecord.TNF_WELL_KNOWN) {
return parseWellKnown(record);
}
//TNF是TNF_ABSOLUTE_URI。即绝对Uri,不使用前缀
else if (tnf == NdefRecord.TNF_ABSOLUTE_URI) {
return parseAbsolute(record);
}
throw new IllegalArgumentException("Unknown TNF " + tnf);
}
/** Parse and absolute URI record */
private static UriRecord parseAbsolute(NdefRecord record) {
//直接将payload转成uri
byte[] payload = record.getPayload();
Uri uri = Uri.parse(new String(payload, Charset.forName("UTF-8")));
return new UriRecord(uri);
}
/** Parse an well known URI record */
private static UriRecord parseWellKnown(NdefRecord record) {
//推断RTD是否为RTD_URI
if (!Arrays.equals(record.getType(), NdefRecord.RTD_URI))
return null;
byte[] payload = record.getPayload();
/*
* payload[0] contains the URI Identifier Code, per the NFC Forum
* "URI Record Type Definition" section 3.2.2.
*
* payload[1]...payload[payload.length - 1] contains the rest of the
* URI.
*/
//payload[0]中包括URI标识代码,也就是URI_PREFIX_MAP中的key
//依据Uri标识代码获取Uri前缀
String prefix = URI_PREFIX_MAP.get(payload[0]);
//获取Uri前缀占用的字节数
byte[] prefixBytes = prefix.getBytes(Charset.forName("UTF-8"));
//为容纳完整的Uri创建一个byte数组
byte[] fullUri = new byte[prefixBytes.length + payload.length - 1];
//将Uri前缀和其余部分组合,形成一个完整的Uri
System.arraycopy(prefixBytes, 0, fullUri, 0, prefixBytes.length);
System.arraycopy(payload, 1, fullUri, prefixBytes.length,
payload.length - 1);
//依据解析出来的Uri创建Uri对象
Uri uri = Uri.parse(new String(fullUri, Charset.forName("UTF-8")));
//创建UriRecord对象并返回
return new UriRecord(uri);
}
}
清单文件:<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="mobile.android.read.write.uri"
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=".ReadWriteUriMainActivity"
android:label="读写NFC标签的Uri"
android:launchMode="singleTask" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="ftp" />
</intent-filter>
</activity>
<activity
android:name=".ShowNFCTagContentActivity"
android:label="显示NFC标签内容" />
<activity
android:name=".UriListActivity"
android:label="选择Uri" />
</application>
</manifest>
AAR样例程序:
AutoRunApplicationActivity:
InstalledApplicationListActivity:package mobile.android.auto.run.application; import java.net.URI; import android.app.Activity; import android.app.PendingIntent; import android.content.Intent; import android.net.Uri; 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.Button; import android.widget.Toast; public class AutoRunApplicationActivity extends Activity { private Button mSelectAutoRunApplication; private String mPackageName; private NfcAdapter mNfcAdapter; private PendingIntent mPendingIntent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_auto_run_application); mSelectAutoRunApplication = (Button) findViewById(R.id.button_select_auto_run_application); //获得默认的NfcAdapter对象 mNfcAdapter = mNfcAdapter.getDefaultAdapter(this); //创建与当前Activity关联的PendingIntent对象 mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0); } //当窗体获得焦点时会提升当前窗体处理NFC标签的优先级 @Override public void onResume() { super.onResume(); //提升当前处理NFC标签的优先级 if (mNfcAdapter != null) mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null); } //当窗体的launchMode被设为singleTop时调用方法(不再调用onCreat方法) @Override public void onNewIntent(Intent intent) { //必须先选择一个Package if (mPackageName == null) return; //获取表示当前标签的对象 Tag detectedTag = intent.getParcelableExtra(mNfcAdapter.EXTRA_TAG); //向标签写入Package writeNFCTag(detectedTag); } //当窗体失去焦点后,应恢复Android系统处理NFC标签的默认状态 @Override public void onPause() { super.onPause(); //恢复处理NFC标签的窗体的默认优先级(禁止当前窗体的优先处理NFC标签) if (mNfcAdapter != null) mNfcAdapter.disableForegroundDispatch(this); } //"选择已安装的应用程序"button的单击事件方法 public void onClick_SelectAutoRunApplication(View view) { Intent intent = new Intent(this, InstalledApplicationListActivity.class); //显示“已安装应用程序”窗体 startActivityForResult(intent, 0); } //向标签写入数据 public void writeNFCTag(Tag tag) { //必须要指定一个Tag对象 if (tag == null) { Toast.makeText(this, "NFC Tag未建立连接", Toast.LENGTH_LONG).show(); return; } //创建NdefMessage对象 //NdefRecord.creatApplicationRecord方法创建一个封装Package的NdefRecord对象 NdefMessage ndefMessage = new NdefMessage( new NdefRecord[] {NdefRecord .createApplicationRecord(mPackageName)}); //获取NdefMessage对象的尺寸 int size = ndefMessage.toByteArray().length; try { //获取Ndef对象 Ndef ndef = Ndef.get(tag); //处理NDEF格式的数据 if (ndef != null) { //同意对标签进行IO操作。连接 ndef.connect(); //NFC标签不是可写的(仅仅读的) if (!ndef.isWritable()) { Toast.makeText(this, "NFC Tag是仅仅读的!", Toast.LENGTH_LONG) .show(); return; } //NFC标签的空间不足 if (ndef.getMaxSize() < size) { Toast.makeText(this, "NFC Tag的空间不足!", Toast.LENGTH_LONG) .show(); return; } //向NFC标签写入数据 ndef.writeNdefMessage(ndefMessage); Toast.makeText(this, "已成功写入数据!
", Toast.LENGTH_LONG).show(); } else { //创建NdefFormatable对象 NdefFormatable format = NdefFormatable.get(tag); if (format != null) { try { //同意标签IO操作,进行连接 format.connect(); //又一次格式化NFC标签,并写入数据 format.format(ndefMessage); Toast.makeText(this, "已成功写入数据!
", Toast.LENGTH_LONG) .show(); } catch (Exception e) { Toast.makeText(this, "写入NDEF格式数据失败!
", Toast.LENGTH_LONG) .show(); } } else { Toast.makeText(this, "NFC标签不支持NDEF格式。", Toast.LENGTH_LONG) .show(); } } } catch (Exception e) { Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == 1) { //更新“选择已安装的应用程序”button的显示文本(Package name和label) mSelectAutoRunApplication.setText(data.getExtras().getString( "package_name")); //以下的代码用于提取Package Name String temp = mSelectAutoRunApplication.getText().toString(); mPackageName = temp.substring(temp.indexOf(" ") + 1); } } }
package mobile.android.auto.run.application;
import java.util.ArrayList;
import java.util.List;
import android.app.ListActivity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
public class InstalledApplicationListActivity extends ListActivity implements
OnItemClickListener {
//用于保存已安装应用程序的Package和Label
private List<String> mPackages = new ArrayList<String>();
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//获得PackageManager对象
PackageManager packageManager = getPackageManager();
//获取系统中已安装的全部应用程序的信息,每个PackageInfo对象表示一个应用程序
List<PackageInfo> packageInfos = packageManager
.getInstalledPackages(PackageManager.GET_ACTIVITIES);
//枚举全部的应用程序信息,从中取出Package和应用程序的Label,中间用“
”分离
for (PackageInfo packageInfo : packageInfos) {
//LoadLabel方法返回的值就是定义Activity时的android:label属性值
mPackages.add(packageInfo.applicationInfo.loadLabel(packageManager)
+ "
" + packageInfo.packageName);
}
//创建一个用于操作Package集合的ArrayAdapter对象
ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, android.R.id.text1,
mPackages);
//在ListView控件中显示全部的Package和程序名
setListAdapter(arrayAdapter);
//指定列表项的单击事件方法
getListView().setOnItemClickListener(this);
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Intent intent = new Intent();
//当单击列表项时,会通过package_name传回Package和Label
intent.putExtra("package_name", mPackages.get(position));
setResult(1, intent);
finish();
}
}
清单文件:<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="mobile.android.auto.run.application"
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=".AutoRunApplicationActivity"
android:label="@string/title_activity_auto_run_application"
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>
<activity
android:name=".InstalledApplicationListActivity"
android:label="@string/title_activity_installed_application_list"
android:screenOrientation="portrait" />
</application>
</manifest>
通过浏览器自己主动打开一个站点:
package mobile.android.auto.open.uri; import android.app.Activity; import android.app.PendingIntent; import android.content.Intent; import android.net.Uri; 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.widget.Toast; public class AutoOpenUriActivity extends Activity { private NfcAdapter nfcAdapter; private PendingIntent pendingIntent; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_auto_open_uri); nfcAdapter = NfcAdapter.getDefaultAdapter(this); pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0); } @Override public void onResume() { super.onResume(); if (nfcAdapter != null) nfcAdapter .enableForegroundDispatch(this, pendingIntent, null, null); } @Override public void onNewIntent(Intent intent) { Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); writeNFCTag(detectedTag); } @Override public void onPause() { super.onPause(); if (nfcAdapter != null) nfcAdapter.disableForegroundDispatch(this); } public void writeNFCTag(Tag tag) { if (tag == null) { Toast.makeText(this, "NFC Tag未建立连接", Toast.LENGTH_LONG).show(); return; } // NdefMessage ndefMessage = new NdefMessage(new NdefRecord[] // { NdefRecord.createUri("http://blog.csdn.net/nokiaguy")}); NdefMessage ndefMessage = new NdefMessage( new NdefRecord[] {NdefRecord.createUri(Uri .parse("http://www.baidu.com"))}); int size = ndefMessage.toByteArray().length; try { Ndef ndef = Ndef.get(tag); if (ndef != null) { ndef.connect(); if (!ndef.isWritable()) { Toast.makeText(this, "NFC Tag是仅仅读的。", Toast.LENGTH_LONG) .show(); return; } if (ndef.getMaxSize() < size) { Toast.makeText(this, "NFC Tag的空间不足!
", Toast.LENGTH_LONG) .show(); return; } ndef.writeNdefMessage(ndefMessage); Toast.makeText(this, "已成功写入数据。", Toast.LENGTH_LONG).show(); } else { NdefFormatable format = NdefFormatable.get(tag); if (format != null) { try { format.connect(); format.format(ndefMessage); Toast.makeText(this, "已成功写入数据。", Toast.LENGTH_LONG) .show(); } catch (Exception e) { Toast.makeText(this, "写入NDEF格式数据失败!", Toast.LENGTH_LONG) .show(); } } else { Toast.makeText(this, "NFC标签不支持NDEF格式!", Toast.LENGTH_LONG) .show(); } } } catch (Exception e) { Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); } } }
附上官方教程:http://developer.android.com/guide/topics/connectivity/nfc/nfc.html