原文地址
检测到标签后在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:
Supported RTDs for TNF_WELL_KNOWN and their mappings:
说明:读取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()方法来获得实际读写的数据。
对应上图中的Payload
Header中的Identifier对应每个Record唯一的Id
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:
- 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);
-
- }
-
- //单击“输入要写入文本”按钮执行的方法
- 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:
- 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() + "\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:
- 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:
- 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;
- }
-
- }
- }
UriListActivity:
- 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();
-
- }
-
- }
ShowNFCTagContentActivity:
- 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() + "\n最大数据容量:" + ndef.getMaxSize()
- + " bytes\n\n";
- 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() + "\n\nUri\n"
- + contentSize + " bytes";
-
- } catch (Exception e) {
- mTagContent.setText(e.getMessage());
- }
- }
-
- }
- }
UriRecord.java
- package 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:
- 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);
-
- }
-
- //"选择已安装的应用程序"按钮的单击事件方法
- 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) {
- //更新“选择已安装的应用程序”按钮的显示文本(Package name和label)
- mSelectAutoRunApplication.setText(data.getExtras().getString(
- "package_name"));
- //下面的代码用于提取Package Name
- String temp = mSelectAutoRunApplication.getText().toString();
- mPackageName = temp.substring(temp.indexOf("\n") + 1);
-
- }
-
- }
-
- }
InstalledApplicationListActivity:
- 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,中间用“\n”分离
- for (PackageInfo packageInfo : packageInfos) {
- //LoadLabel方法返回的值就是定义Activity时的android:label属性值
- mPackages.add(packageInfo.applicationInfo.loadLabel(packageManager)
- + "\n" + 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