NFC(10)NDEF uri格式规范及读写示例(解析与封装ndef uri)
只有遵守NDEF uri 格式规范的数据才能写到nfc标签上.
NDEF uri 格式规范
uri 只有两部分:
第1个字节是uri协议映射值,如:0x01 表示uri以 http://www.开头.
然后是uri的内容 ,如 www.g.cn
uri协议映射值表
示例
ReadWriteUriActivity.java
1 import android.app.Activity; 2 import android.content.Intent; 3 import android.nfc.NdefMessage; 4 import android.nfc.NdefRecord; 5 import android.nfc.NfcAdapter; 6 import android.nfc.Tag; 7 import android.nfc.tech.Ndef; 8 import android.os.Bundle; 9 import android.view.View; 10 import android.widget.TextView; 11 import android.widget.Toast; 12 13 /* 14 * 本apk主activity,拦截nfc标签事件 15 * 把读到的内容传给ShowNFCTagContentActivity 16 * 把封装好的uri写到临近的nfc标签. 17 */ 18 public class ReadWriteUriMainActivity extends Activity { 19 private TextView mSelectUri; 20 private String mUri; 21 22 @Override 23 public void onCreate(Bundle savedInstanceState) { 24 super.onCreate(savedInstanceState); 25 setContentView(R.layout.activity_read_write_uri_main); 26 mSelectUri = (TextView) findViewById(R.id.textview_uri); 27 28 } 29 30 public void onClick_SelectUri(View view) { 31 Intent intent = new Intent(this, UriListActivity.class); 32 startActivityForResult(intent, 1); 33 34 } 35 36 @Override 37 protected void onActivityResult(int requestCode, int resultCode, Intent data) { 38 if (requestCode == 1 && resultCode == 1) { 39 mUri = data.getStringExtra("uri"); 40 mSelectUri.setText(mUri); 41 } 42 } 43 44 /* 45 * 如果本aty中的mUri空,就读nfc标签内容存到mUri中, 46 * 不空就封装uri并把它写到nfc标签中 47 */ 48 @Override 49 public void onNewIntent(Intent intent) { 50 if (mUri == null) {//读nfc标签内容存到mUri中,并显示 51 //把读到的内容传给ShowNFCTagContentActivity 52 Intent myIntent = new Intent(this, ShowNFCTagContentActivity.class); 53 myIntent.putExtras(intent); 54 myIntent.setAction(NfcAdapter.ACTION_NDEF_DISCOVERED); 55 startActivity(myIntent); 56 } else {// 封装uri并把它写到nfc标签中 57 58 //封装uri并把它写到nfc标签 第1步,取nfc标签 59 Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 60 61 //封装uri并把它写到nfc标签 第2步,构造NdefMessage,其中有NdefRecord,NdefRecord中有封装的uri 62 NdefMessage ndefMessage = new NdefMessage( 63 new NdefRecord[] { createUriRecord(mUri) }); 64 65 //封装uri并把它写到nfc标签 第3步,封装uri并写入 66 if (writeTag(ndefMessage, tag)) { 67 mUri = null; 68 mSelectUri.setText(""); 69 } 70 } 71 } 72 73 /* 74 * 封装uri格式数据 75 * 现部分组成: 第一个字节是uri协议映射值 76 * uri协议映射值,如:0x01 表示uri以 http://www.开头. 77 * uri的内容 如:www.g.cn 78 */ 79 public NdefRecord createUriRecord(String uriStr) { 80 /* 81 * 封装uri格式数据 第1步, 根据uriStr中的值找到构造第一个字节的内容:uri协议映射值 82 */ 83 byte prefix = 0; 84 for (Byte b : UriRecord.URI_PREFIX_MAP.keySet()) { 85 String prefixStr = UriRecord.URI_PREFIX_MAP.get(b).toLowerCase(); 86 if ("".equals(prefixStr)) 87 continue; 88 if (uriStr.toLowerCase().startsWith(prefixStr)) { 89 prefix = b; 90 uriStr = uriStr.substring(prefixStr.length()); 91 break; 92 } 93 94 } 95 /* 96 * 封装uri格式数据 第2步, uri的内容就是本函数的参数 uriStr 97 */ 98 /* 99 * 封装uri格式数据 第3步, 申请分配空间 100 */ 101 byte[] data = new byte[1 + uriStr.length()]; 102 103 /* 104 * 封装uri格式数据 第4步, 把uri头的映射值和uri内容写到刚申请的空间中 105 */ 106 data[0] = prefix; 107 System.arraycopy(uriStr.getBytes(), 0, data, 1, uriStr.length()); 108 109 /* 110 * 封装uri格式数据 第5步, 根据uri构造一个NdefRecord 111 */ 112 NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, 113 NdefRecord.RTD_URI, new byte[0], data); 114 return record; 115 } 116 117 /* 118 * 将封装好uri格式的NdefMessage写入到nfc标签中. 119 */ 120 boolean writeTag(NdefMessage message, Tag tag) { 121 int size = message.toByteArray().length; 122 try { 123 Ndef ndef = Ndef.get(tag); 124 if (ndef != null) { 125 ndef.connect(); 126 if (!ndef.isWritable()) { 127 return false; 128 } 129 if (ndef.getMaxSize() < size) { 130 return false; 131 } 132 ndef.writeNdefMessage(message); 133 Toast.makeText(this, "ok", Toast.LENGTH_LONG).show(); 134 return true; 135 } 136 } catch (Exception e) { 137 e.printStackTrace(); 138 } 139 return false; 140 } 141 }
UriRecord.java
1 import java.nio.charset.Charset; 2 import java.util.Arrays; 3 import java.util.HashMap; 4 import java.util.Map; 5 import android.net.Uri; 6 import android.nfc.NdefRecord; 7 8 public class UriRecord { 9 10 private final Uri mUri;// 存uri 11 12 /* 13 * uri 格式数据中 第一个字节 存uri的头值映射表 14 * 如 0x01 表示uri以 http://www.开头, 15 * 存uri的头值是为了省空间. 16 */ 17 public static final Map<Byte, String> URI_PREFIX_MAP = new HashMap<Byte, String>(); 18 19 static { 20 URI_PREFIX_MAP.put((byte) 0x00, ""); 21 URI_PREFIX_MAP.put((byte) 0x01, "http://www."); 22 URI_PREFIX_MAP.put((byte) 0x02, "https://www."); 23 URI_PREFIX_MAP.put((byte) 0x03, "http://"); 24 URI_PREFIX_MAP.put((byte) 0x04, "https://"); 25 URI_PREFIX_MAP.put((byte) 0x05, "tel:"); 26 URI_PREFIX_MAP.put((byte) 0x06, "mailto:"); 27 URI_PREFIX_MAP.put((byte) 0x07, "ftp://anonymous:anonymous@"); 28 URI_PREFIX_MAP.put((byte) 0x08, "ftp://ftp."); 29 URI_PREFIX_MAP.put((byte) 0x09, "ftps://"); 30 URI_PREFIX_MAP.put((byte) 0x0A, "sftp://"); 31 URI_PREFIX_MAP.put((byte) 0x0B, "smb://"); 32 URI_PREFIX_MAP.put((byte) 0x0C, "nfs://"); 33 URI_PREFIX_MAP.put((byte) 0x0D, "ftp://"); 34 URI_PREFIX_MAP.put((byte) 0x0E, "dav://"); 35 URI_PREFIX_MAP.put((byte) 0x0F, "news:"); 36 URI_PREFIX_MAP.put((byte) 0x10, "telnet://"); 37 URI_PREFIX_MAP.put((byte) 0x11, "imap:"); 38 URI_PREFIX_MAP.put((byte) 0x12, "rtsp://"); 39 URI_PREFIX_MAP.put((byte) 0x13, "urn:"); 40 URI_PREFIX_MAP.put((byte) 0x14, "pop:"); 41 URI_PREFIX_MAP.put((byte) 0x15, "sip:"); 42 URI_PREFIX_MAP.put((byte) 0x16, "sips:"); 43 URI_PREFIX_MAP.put((byte) 0x17, "tftp:"); 44 URI_PREFIX_MAP.put((byte) 0x18, "btspp://"); 45 URI_PREFIX_MAP.put((byte) 0x19, "btl2cap://"); 46 URI_PREFIX_MAP.put((byte) 0x1A, "btgoep://"); 47 URI_PREFIX_MAP.put((byte) 0x1B, "tcpobex://"); 48 URI_PREFIX_MAP.put((byte) 0x1C, "irdaobex://"); 49 URI_PREFIX_MAP.put((byte) 0x1D, "file://"); 50 URI_PREFIX_MAP.put((byte) 0x1E, "urn:epc:id:"); 51 URI_PREFIX_MAP.put((byte) 0x1F, "urn:epc:tag:"); 52 URI_PREFIX_MAP.put((byte) 0x20, "urn:epc:pat:"); 53 URI_PREFIX_MAP.put((byte) 0x21, "urn:epc:raw:"); 54 URI_PREFIX_MAP.put((byte) 0x22, "urn:epc:"); 55 URI_PREFIX_MAP.put((byte) 0x23, "urn:nfc:"); 56 } 57 58 private UriRecord(Uri uri) { 59 this.mUri = uri; 60 } 61 62 public Uri getUri() { 63 return mUri; 64 } 65 66 /* 67 * 这时,uri数据里没有uri头值,整个uri数据就是一个uri 68 */ 69 private static UriRecord parseAbsolute(NdefRecord ndefRecord) { 70 //1,取得数据流 71 byte[] payload = ndefRecord.getPayload(); 72 //2,解析出一个uri 73 String uriStr = new String(payload, Charset.forName("UTF-8")); 74 Uri uri = Uri.parse(uriStr); 75 return new UriRecord(uri); 76 77 } 78 /* 79 * 解析nfc uri格式的数据 80 * 81 */ 82 private static UriRecord parseWellKnown(NdefRecord ndefRecord) { 83 //解析uri第1步,判断record中是否是 uri 84 if (!Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_URI)) 85 return null; 86 //解析uri第2步,获取字节数据. 87 byte[] payload = ndefRecord.getPayload(); 88 89 //解析uri第3步,解析出uri头,如https://等 90 String prefix = URI_PREFIX_MAP.get(payload[0]); 91 //解析uri第4步,解析出uri的内容,如:www.g.cn 92 byte[] prefixBytes = prefix.getBytes(Charset.forName("UTF-8")); 93 94 //解析uri第5步,合并uri头各内容. 95 byte[] fullUri = new byte[prefixBytes.length + payload.length - 1]; 96 System.arraycopy(prefixBytes, 0, fullUri, 0, prefixBytes.length); 97 System.arraycopy(payload, 1, fullUri, prefixBytes.length,payload.length - 1); 98 //解析uri第6步,构造Uri 99 String fullUriStr = new String(fullUri, Charset.forName("UTF-8")); 100 Uri uri = Uri.parse(fullUriStr); 101 //解析uri第7步, 102 return new UriRecord(uri); 103 104 } 105 /* 106 * 解析uri格式数据. 107 */ 108 public static UriRecord parse(NdefRecord record) { 109 short tnf = record.getTnf(); 110 if (tnf == NdefRecord.TNF_WELL_KNOWN) { 111 return parseWellKnown(record); 112 } else if (tnf == NdefRecord.TNF_ABSOLUTE_URI) { 113 return parseAbsolute(record); 114 } 115 throw new IllegalArgumentException("Unknown TNF " + tnf); 116 } 117 }