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

\


NdefRecZ喎�"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcmTW0LXEs6PTw7e9t6g8L3N0cm9uZz48YnI+CjwvcD4KPHA+MS6/yc2ouf1OZGVmUmVjb3JkLmdldFRuZigpt723qMC0u/G1w1RORtfWts6juzwvcD4KPHA+Mi7NqLn9TmRlZlJlY29yZC5nZXRUeXBlKCm3vbeowLS78bXDUlRE19a2zqOstbFUTkbOqlRORl9XRUxMX0tOT1dOyrG1xFJURKGjPC9wPgo8cD4zLs2ouf1OZGVmUmVjb3JkLmdldFBheWxvYWQoKbe9t6jAtLvxtcPKtbzKtsHQtLXEyv2+3aGjPC9wPgo8cD48YnI+CjwvcD4KPHA+PGJyPgo8L3A+CjxwPjxzdHJvbmc+TkRFRs7Esb4mIzI2Njg0O8q9PC9zdHJvbmc+PGJyPgo8L3A+CjxwPk5kZWZNZXNzYWdl1tC1xHBheWxhb2S+zcrHyrW8yrXEyv2+3aOsxuTW0E5ERUbOxLG+JiMyNjY4NDvKvc6qo7o8YnI+CjwvcD4KPHA+PGltZyBzcmM9"http://www.2cto.com/uploadfile/Collfiles/20140430/20140430090648250.png" alt="\">


NDEF Uri格式

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

\

2、前缀需要查表解析



例子程序:

ReadWriteTextMainActivity:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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);
         }
     }
}


Android Manifest.xml:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<manifest android:versionname= "1.0" android:versioncode= "1" package = "mobile.android.read.write.text" xmlns:android= "http://schemas.android.com/apk/res/android" >
 
     <uses-sdk android:targetsdkversion= "15" android:minsdkversion= "15" >
 
     <uses-permission android:name= "android.permission.NFC" >
 
     
         
             <intent-filter>
                 
                 <category android:name= "android.intent.category.LAUNCHER" >
             </category>
             <intent-filter>
                 
                 <category android:name= "android.intent.category.DEFAULT" >
                 <data android:mimetype= "text/plain" >
             </data>
         </category>
         
         
     </activity>
</activity></action></intent-filter></action></intent-filter></activity></application></uses-permission></uses-sdk></manifest>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值