首页 > 代码库 > android nfc中Ndef格式的读写

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信息结构



NdefRecord中的常用方法

1.可通过NdefRecord.getTnf()方法来获得TNF字段;

2.通过NdefRecord.getType()方法来获得RTD字段,当TNF为TNF_WELL_KNOWN时的RTD。

3.通过NdefRecord.getPayload()方法来获得实际读写的数据。



NDEF文本格式

NdefMessage中的paylaod就是实际的数据,其中NDEF文本格式为:



NDEF Uri格式

1、NdefMessage中的paylaod就是实际的数据,其中NDEF文本格式为:


2、前缀需要查表解析



例子程序:

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 = http://www.mamicode.com/new byte[1 + langBytes.length + textBytes.length];>
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>