android NFC開發
先說說NFC開發總結,看了幾天NFC開發資料,搜集了不少關於這方面的資料、demo、以及他人的總結。以下有部分是摘錄總結的。因為要是現在總結也是那些,最後附送代碼。關於demo我也有,有需要在評論去發郵箱給我。
一、NFC的配置總結
第一:螢幕沒有鎖住 。 第二:NFC功能已經在設定中開啟
當系統檢測到一個NFC標籤的時候,他會自動去尋找最合適的activity去處理這個intent.
NFC發出的這個Intent將會有三種action:
ACTION_NDEF_DISCOVERED:當系統檢測到tag中含有NDEF格式的資料時,且系統中有activity聲明可以接受包含NDEF資料的Intent的時候,系統會優先發出這個action的intent。
ACTION_TECH_DISCOVERED:當沒有任何一個activity聲明自己可以響應ACTION_NDEF_DISCOVERED時,系統會嘗試發出TECH的intent.即便你的tag中所包含的資料是NDEF的,但是如果這個資料的MIMEtype或URI不能和任何一個activity所聲明的想吻合,系統也一樣會嘗試發出tech格式的intent,而不是NDEF.
ACTION_TAG_DISCOVERED:當系統發現前兩個intent在系統中無人會接受的時候,就只好發這個預設的TAG類型的
二、NFC相關androidManifest檔案設定
首先是許可權:
然後是sdk層級限制:我個人建議API11開始比較合適:
如果是API8,在代碼中,nfc功能設定的代碼會出錯,要拋出
例如:
NfcAdapter mAdapter = NfcAdapter.getDefaultAdapter(this);
mAdapter.isEnabled()
接著是特殊功能限制:
這個生命可以讓你的應用在googleplay上被聲明使用者必須擁有nfc功能。
三、NFC標籤過濾,也在androidManifest檔案設定
在activity的intent過濾xml聲明中,你可以同時聲明過濾這三種action.但是由之前所說,你應該知道系統在發送intent的時候是有優先順序的,所以你最好清楚自己最想處理哪個。
1:過濾ACTION_TAG_DISCOVERED:
這個最簡單,也是最後一個被嘗試接受intent的選項。
2:過濾ACTION_NDEF_DISCOVERED:
其中最重要的應該算是data的mimeType類型了,這個定義的越準確,intent指向你這個activity的成功率就越高,否則系統可能不會發出你想要的NDEF intent了。下面在講如何使用NDEF寫入NFC標籤的時候會多舉幾個類型的例子。
3:過濾ACTION_TECH_DISCOVERED:
你首先需要在你的/res/xml下面建立一個過濾規則檔案。名字任取,比如可以叫做nfc_tech_filter.xml。這個裡面定義的是nfc實現的各種標準,每一個nfc卡都會符合多個不同的標準,個人理解為這些標準有些相互之間也是相容的。你可以在檢測到nfc標籤後使用getTechList()方法來查看你所檢測的tag到底支援哪些nfc標準。
一個nfc_tech_filter.xml中可以定義多個結構組。
android.nfc.tech.IsoDep android.nfc.tech.NfcA android.nfc.tech.NfcB android.nfc.tech.NfcF android.nfc.tech.NfcV android.nfc.tech.Ndef android.nfc.tech.NdefFormatable android.nfc.tech.MifareClassic android.nfc.tech.MifareUltralight
在androidManifest檔案中聲明xml過濾的舉例如下:
四、看具體代碼:
1、主要代碼實現如下:
package org.reno.Beam;import java.io.ByteArrayOutputStream;import java.nio.charset.Charset;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import java.util.List;import java.util.Locale;import org.nfc.read.ParsedNdefRecord;import android.app.Activity;import android.app.AlertDialog;import android.app.PendingIntent;import android.content.DialogInterface;import android.content.Intent;import android.nfc.NdefMessage;import android.nfc.NdefRecord;import android.nfc.NfcAdapter;import android.nfc.Tag;import android.nfc.tech.MifareClassic;import android.nfc.tech.MifareUltralight;import android.os.Bundle;import android.os.Parcelable;import android.provider.Settings;import android.widget.TextView;public class MainActivity extends Activity {private static final DateFormat TIME_FORMAT = SimpleDateFormat.getDateTimeInstance();private NfcAdapter mAdapter;private PendingIntent mPendingIntent;private NdefMessage mNdefPushMessage;private TextView promt;private AlertDialog mDialog;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);promt = (TextView) findViewById(R.id.promt);resolveIntent(getIntent());mDialog = new AlertDialog.Builder(this).setNeutralButton("Ok", null).create();// 擷取預設的NFC控制器mAdapter = NfcAdapter.getDefaultAdapter(this);//攔截系統級的NFC掃描,例如掃描藍芽mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);mNdefPushMessage = new NdefMessage(new NdefRecord[] { newTextRecord("",Locale.ENGLISH, true) });}@Overrideprotected void onResume() {super.onResume();if (mAdapter == null) {if (!mAdapter.isEnabled()) {showWirelessSettingsDialog();}showMessage(R.string.error, R.string.no_nfc);promt.setText("裝置不支援NFC!");return;}if (!mAdapter.isEnabled()) {promt.setText("請在系統設定中先啟用NFC功能!");return;}if (mAdapter != null) {//隱式啟動mAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);mAdapter.enableForegroundNdefPush(this, mNdefPushMessage);}}@Overrideprotected void onPause() {super.onPause();if (mAdapter != null) {//隱式啟動mAdapter.disableForegroundDispatch(this);mAdapter.disableForegroundNdefPush(this);}}//16進位字串轉換為Stringprivate String hexString = "0123456789ABCDEF";public String decode(String bytes) {if (bytes.length() != 30) {return null;}ByteArrayOutputStream baos = new ByteArrayOutputStream(bytes.length() / 2);// 將每2位16進位整數組裝成一個位元組for (int i = 0; i < bytes.length(); i += 2)baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString.indexOf(bytes.charAt(i + 1))));return new String(baos.toByteArray());}// 字元序列轉換為16進位字串private static String bytesToHexString(byte[] src, boolean isPrefix) {StringBuilder stringBuilder = new StringBuilder();if (isPrefix == true) {stringBuilder.append("0x");}if (src == null || src.length <= 0) {return null;}char[] buffer = new char[2];for (int i = 0; i < src.length; i++) {buffer[0] = Character.toUpperCase(Character.forDigit((src[i] >>> 4) & 0x0F, 16));buffer[1] = Character.toUpperCase(Character.forDigit(src[i] & 0x0F,16));System.out.println(buffer);stringBuilder.append(buffer);}return stringBuilder.toString();}private void showMessage(int title, int message) {mDialog.setTitle(title);mDialog.setMessage(getText(message));mDialog.show();}private NdefRecord newTextRecord(String text, Locale locale,boolean encodeInUtf8) {byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");byte[] textBytes = text.getBytes(utfEncoding);int utfBit = encodeInUtf8 ? 0 : (1 << 7);char status = (char) (utfBit + langBytes.length);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);return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT,new byte[0], data);}private void showWirelessSettingsDialog() {AlertDialog.Builder builder = new AlertDialog.Builder(this);builder.setMessage(R.string.nfc_disabled);builder.setPositiveButton(android.R.string.ok,new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialogInterface, int i) {Intent intent = new Intent(Settings.ACTION_WIRELESS_SETTINGS);startActivity(intent);}});builder.setNegativeButton(android.R.string.cancel,new DialogInterface.OnClickListener() {public void onClick(DialogInterface dialogInterface, int i) {finish();}});builder.create().show();return;}//初步判斷是什麼類型NFC卡private void resolveIntent(Intent intent) {String action = intent.getAction();if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)|| NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);NdefMessage[] msgs;if (rawMsgs != null) {msgs = new NdefMessage[rawMsgs.length];for (int i = 0; i < rawMsgs.length; i++) {msgs[i] = (NdefMessage) rawMsgs[i];}} else {// Unknown tag typebyte[] empty = new byte[0];byte[] id = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);Parcelable tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);byte[] payload = dumpTagData(tag).getBytes();NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN,empty, id, payload);NdefMessage msg = new NdefMessage(new NdefRecord[] { record });msgs = new NdefMessage[] { msg };}// Setup the viewsbuildTagViews(msgs);}}//一般公家卡,掃描的資訊private String dumpTagData(Parcelable p) {StringBuilder sb = new StringBuilder();Tag tag = (Tag) p;byte[] id = tag.getId();sb.append("Tag ID (hex): ").append(getHex(id)).append("\n");sb.append("Tag ID (dec): ").append(getDec(id)).append("\n");sb.append("ID (reversed): ").append(getReversed(id)).append("\n");String prefix = "android.nfc.tech.";sb.append("Technologies: ");for (String tech : tag.getTechList()) {sb.append(tech.substring(prefix.length()));sb.append(", ");}sb.delete(sb.length() - 2, sb.length());for (String tech : tag.getTechList()) {if (tech.equals(MifareClassic.class.getName())) {sb.append('\n');MifareClassic mifareTag = MifareClassic.get(tag);String type = "Unknown";switch (mifareTag.getType()) {case MifareClassic.TYPE_CLASSIC:type = "Classic";break;case MifareClassic.TYPE_PLUS:type = "Plus";break;case MifareClassic.TYPE_PRO:type = "Pro";break;}sb.append("Mifare Classic type: ");sb.append(type);sb.append('\n');sb.append("Mifare size: ");sb.append(mifareTag.getSize() + " bytes");sb.append('\n');sb.append("Mifare sectors: ");sb.append(mifareTag.getSectorCount());sb.append('\n');sb.append("Mifare blocks: ");sb.append(mifareTag.getBlockCount());}if (tech.equals(MifareUltralight.class.getName())) {sb.append('\n');MifareUltralight mifareUlTag = MifareUltralight.get(tag);String type = "Unknown";switch (mifareUlTag.getType()) {case MifareUltralight.TYPE_ULTRALIGHT:type = "Ultralight";break;case MifareUltralight.TYPE_ULTRALIGHT_C:type = "Ultralight C";break;}sb.append("Mifare Ultralight type: ");sb.append(type);}}return sb.toString();}private String getHex(byte[] bytes) {StringBuilder sb = new StringBuilder();for (int i = bytes.length - 1; i >= 0; --i) {int b = bytes[i] & 0xff;if (b < 0x10)sb.append('0');sb.append(Integer.toHexString(b));if (i > 0) {sb.append(" ");}}return sb.toString();}private long getDec(byte[] bytes) {long result = 0;long factor = 1;for (int i = 0; i < bytes.length; ++i) {long value = bytes[i] & 0xffl;result += value * factor;factor *= 256l;}return result;}private long getReversed(byte[] bytes) {long result = 0;long factor = 1;for (int i = bytes.length - 1; i >= 0; --i) {long value = bytes[i] & 0xffl;result += value * factor;factor *= 256l;}return result;}//顯示NFC掃描的資料private void buildTagViews(NdefMessage[] msgs) {if (msgs == null || msgs.length == 0) {return;}// Parse the first message in the list// Build views for all of the sub recordsDate now = new Date();List records = NdefMessageParser.parse(msgs[0]);final int size = records.size();for (int i = 0; i < size; i++) {TextView timeView = new TextView(this);timeView.setText(TIME_FORMAT.format(now));ParsedNdefRecord record = records.get(i);promt.append(record.getViewText());}}//擷取系統隱式啟動的@Overridepublic void onNewIntent(Intent intent) {setIntent(intent);resolveIntent(intent);}}
2、androidManifest配置