`
qilixiang012
  • 浏览: 202641 次
文章分类
社区版块
存档分类
最新评论

android nfc中Ndef格式的读写

 
阅读更多

检测到标签后在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 toACTION_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 toACTION_TECH_DISCOVERED.
TNF_UNKNOWN Falls back toACTION_TECH_DISCOVERED.
TNF_WELL_KNOWN MIME type or URI depending on the Record Type Definition (RTD), which you set in the type field. SeeTable 2.for more information on available RTDs and their mappings.
Supported RTDs for TNF_WELL_KNOWN and their mappings:

Record Type Definition (RTD) Mapping
RTD_ALTERNATIVE_CARRIER Falls back toACTION_TECH_DISCOVERED.
RTD_HANDOVER_CARRIER Falls back toACTION_TECH_DISCOVERED.
RTD_HANDOVER_REQUEST Falls back toACTION_TECH_DISCOVERED.
RTD_HANDOVER_SELECT Falls back toACTION_TECH_DISCOVERED.
RTD_SMART_POSTER URI based on parsing the payload.
RTD_TEXT MIME type oftext/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()方法来获得实际读写的数据。

对应上图中的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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics