1 // 从NdefRecord对象中解析出实际的Uri 2 public class UriRecord { 3 public static final Map<Byte, String> URI_PREFIX_MAP = new HashMap<Byte, String>();// 映射Uri前缀和对应的值 4 static { 5 // 设置NDEF Uri规范支持的Uri前缀,在解析payload时,在解析payload时,需根据payload的第1个字节定位相应的Uri前缀 6 URI_PREFIX_MAP.put((byte) 0x00, ""); 7 URI_PREFIX_MAP.put((byte) 0x01, "http://www."); 8 URI_PREFIX_MAP.put((byte) 0x02, "https://www."); 9 URI_PREFIX_MAP.put((byte) 0x03, "http://"); 10 URI_PREFIX_MAP.put((byte) 0x04, "https://"); 11 URI_PREFIX_MAP.put((byte) 0x05, "tel:"); 12 URI_PREFIX_MAP.put((byte) 0x06, "mailto:"); 13 URI_PREFIX_MAP.put((byte) 0x07, "ftp://anonymous:[email protected]"); 14 URI_PREFIX_MAP.put((byte) 0x08, "ftp://ftp."); 15 URI_PREFIX_MAP.put((byte) 0x09, "ftps://"); 16 URI_PREFIX_MAP.put((byte) 0x0A, "sftp://"); 17 URI_PREFIX_MAP.put((byte) 0x0B, "smb://"); 18 URI_PREFIX_MAP.put((byte) 0x0C, "nfs://"); 19 URI_PREFIX_MAP.put((byte) 0x0D, "ftp://"); 20 URI_PREFIX_MAP.put((byte) 0x0E, "dav://"); 21 URI_PREFIX_MAP.put((byte) 0x0F, "news:"); 22 URI_PREFIX_MAP.put((byte) 0x10, "telnet://"); 23 URI_PREFIX_MAP.put((byte) 0x11, "imap:"); 24 URI_PREFIX_MAP.put((byte) 0x12, "rtsp://"); 25 URI_PREFIX_MAP.put((byte) 0x13, "urn:"); 26 URI_PREFIX_MAP.put((byte) 0x14, "pop:"); 27 URI_PREFIX_MAP.put((byte) 0x15, "sip:"); 28 URI_PREFIX_MAP.put((byte) 0x16, "sips:"); 29 URI_PREFIX_MAP.put((byte) 0x17, "tftp:"); 30 URI_PREFIX_MAP.put((byte) 0x18, "btspp://"); 31 URI_PREFIX_MAP.put((byte) 0x19, "btl2cap://"); 32 URI_PREFIX_MAP.put((byte) 0x1A, "btgoep://"); 33 URI_PREFIX_MAP.put((byte) 0x1B, "tcpobex://"); 34 URI_PREFIX_MAP.put((byte) 0x1C, "irdaobex://"); 35 URI_PREFIX_MAP.put((byte) 0x1D, "file://"); 36 URI_PREFIX_MAP.put((byte) 0x1E, "urn:epc:id:"); 37 URI_PREFIX_MAP.put((byte) 0x1F, "urn:epc:tag:"); 38 URI_PREFIX_MAP.put((byte) 0x20, "urn:epc:pat:"); 39 URI_PREFIX_MAP.put((byte) 0x21, "urn:epc:raw:"); 40 URI_PREFIX_MAP.put((byte) 0x22, "urn:epc:"); 41 URI_PREFIX_MAP.put((byte) 0x23, "urn:nfc:"); 42 } 43 44 private final Uri mUri; 45 46 private UriRecord(Uri uri) { 47 this.mUri = uri; 48 } 49 50 // 获取已解析出的Uri 51 public Uri getUri() { 52 return mUri; 53 } 54 55 // 分析NdefRecord对象中的payload,并创建封装Uri的UriRecord对象 56 public static UriRecord parse(NdefRecord record) { 57 short tnf = record.getTnf(); 58 // TNF是TNF_WELL_KNOWN,也就是使用了Uri前缀 59 if (tnf == NdefRecord.TNF_WELL_KNOWN) { 60 return parseWellKnown(record); 61 }// TNF是TNF_ABSOLUTE_URI,也就是绝对Uri(不使用Uri前缀) 62 else if (tnf == NdefRecord.TNF_ABSOLUTE_URI) { 63 return parseAbsolute(record); 64 } 65 throw new IllegalArgumentException("Unknown TNF " + tnf); 66 } 67 68 // 分析绝对Uri 69 private static UriRecord parseAbsolute(NdefRecord record) { 70 byte[] payload = record.getPayload(); 71 Uri uri = Uri.parse(new String(payload, Charset.forName("UTF-8")));// 直接将payload转成Uri 72 return new UriRecord(uri); 73 } 74 75 // 处理已知类型的Uri,即使用Uri前缀形式表示的Uri 76 private static UriRecord parseWellKnown(NdefRecord record) { 77 // 判断RTD是否为RTD_URI 78 if (!Arrays.equals(record.getType(), NdefRecord.RTD_URI)) 79 return null; 80 byte[] payload = record.getPayload(); 81 82 // payload[0]包含URI标识代码,即URI_PREFIX_MAP中的key,payload[1]…payload[payload.length-1]包含Uri的其余部分URI。 83 String prefix = URI_PREFIX_MAP.get(payload[0]);// 根据Uri标识代码获取Uri前缀 84 byte[] prefixBytes = prefix.getBytes(Charset.forName("UTF-8"));// 获取Uri前缀占用的字节数 85 byte[] fullUri = new byte[prefixBytes.length + payload.length - 1];// 为容纳完整的Uri创建一个byte数组 86 // 下面两行代码将Uri前缀和Uri的其余部分组合,形成一个完整的Uri 87 System.arraycopy(prefixBytes, 0, fullUri, 0, prefixBytes.length); 88 System.arraycopy(payload, 1, fullUri, prefixBytes.length, 89 payload.length - 1); 90 Uri uri = Uri.parse(new String(fullUri, Charset.forName("UTF-8")));// 根据解析出来的Uri创建Uri对象 91 return new UriRecord(uri);// 创建UriRecord对象并返回 92 } 93 }
UriRecord.java
1 // 显示NFC标签中的Uri 2 public class ShowNFCTagContentActivity extends Activity { 3 private TextView mTagContent; 4 private Tag mDetectedTag; 5 private String mTagText; 6 7 @Override 8 public void onCreate(Bundle savedInstanceState) { 9 super.onCreate(savedInstanceState); 10 setContentView(R.layout.activity_show_nfctag_content); 11 mTagContent = (TextView) findViewById(R.id.textview_tag_content); 12 mDetectedTag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG); 13 Ndef ndef = Ndef.get(mDetectedTag); 14 mTagText = ndef.getType() + "\n最大数据容量:" + ndef.getMaxSize() 15 + " bytes\n\n"; 16 readNFCTag(); 17 mTagContent.setText(mTagText); 18 } 19 20 // 读取NFC标签中的数据 21 private void readNFCTag() { 22 if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { 23 24 Parcelable[] rawMsgs = getIntent().getParcelableArrayExtra( 25 NfcAdapter.EXTRA_NDEF_MESSAGES); 26 27 NdefMessage ndefMessage = null; 28 int contentSize = 0; 29 if (rawMsgs != null) { 30 31 if (rawMsgs.length > 0) { 32 ndefMessage = (NdefMessage) rawMsgs[0];// 只取第一个NdefMessage对象 33 contentSize = ndefMessage.toByteArray().length;// 获取NFC标签存储的数据占用的大小(bytes) 34 } else { 35 return; 36 } 37 } 38 try { 39 NdefRecord record = ndefMessage.getRecords()[0];// 取第1个NdefMessage对象的第1个NdefRecord对象 40 UriRecord uriRecord = UriRecord 41 .parse(ndefMessage.getRecords()[0]);// 分析NdefRecord对象中的数据,并创建了UriRecord对象 42 mTagText += uriRecord.getUri().toString() + "\n\nUri\n" 43 + contentSize + " bytes";// 获取Uri等信息,这些信息会显示在当前窗口上 44 } catch (Exception e) { 45 mTagContent.setText(e.getMessage()); 46 } 47 } 48 } 49 }
ShowNFCTagContentActivity.java
<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> <!-- 下面的配置能检测到http、https和ftp协议的NDEF Uri格式的NFC标签,无法识别其他协议的NFC标签。当然也可添加更多的Uri协议 --> <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>
AndroidManifest.xml
注意:
- 由于本例是直接在AndroidManifest.xml文件中指定了NFC的相关Action,故即使程序退出,这些Action仍然会起作用。这时系统就不会再使用默认的NFC处理程序来处理NDEF Uri格式的NFC标签了,除非卸载这些程序。
- 本例实现的ReadWriteUriMainActivity.createUriRecord方法与NdefRecord.createUri方法的实现原理类似,都使用了一个Uri前缀与相应的标识代码的映射,利用这个映射将实际的Uri前缀转换成用字节表示的标识代码(可自行查看NdefRecord.createUri方法的源代码)。
时间: 2024-11-08 19:34:28