Android NFC(二)

上一篇中,簡單的介紹了下nfc的相關(guān)知識,這一篇將以代碼的形式更深入的理解nfc。

一、準(zhǔn)備工作

首先肯定要申請相應(yīng)的權(quán)限:
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
同時要注意最小api的版本,根據(jù)谷歌官方的說話,NFC在Android上,也是從API9才開始支持的,但是到了API14 Google才對NFC大力開發(fā),所以等到了API15的時候,NFC的傳輸速度就得到了很大的加強(qiáng),所以最小api最好設(shè)置為14.
<uses-sdk android:minSdkVersion="14"/>
然后在相應(yīng)的要接收nfc信息的activity中注冊intent filter:

            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
                <data android:mimeType="text/plain"/>
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED"/>
            </intent-filter>

            <meta-data
                android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter"/>
            <intent-filter>
                <action android:name="android.nfc.action.TAG_DISCOVERED"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>

如果您的活動過濾器是ACTION_TECH_DISCOVERED,你必須創(chuàng)建一個指定的活動支持內(nèi)技術(shù)的XML資源文件,可以通過android.nfc.Tag類的getTechList()獲取子集
其中名為nfc_tech_filter的xml文件如下:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
          
        <tech>android.nfc.tech.IsoDep</tech>
          
        <tech>android.nfc.tech.NfcA</tech>
          
        <tech>android.nfc.tech.NfcB</tech>
          
        <tech>android.nfc.tech.NfcF</tech>
          
        <tech>android.nfc.tech.NfcV</tech>
          
        <tech>android.nfc.tech.Ndef</tech>
          
        <tech>android.nfc.tech.NdefFormatable</tech>
          
        <tech>android.nfc.tech.MifareClassic</tech>
          
        <tech>android.nfc.tech.MifareUltralight</tech>
          
    </tech-list>
</resources>

當(dāng)然您也可以指定多個tech-list組。每個的tech-list集獨立地考慮,并且您的活動被認(rèn)為是一個匹配,如果任何一個 tech-list組是由返回的技術(shù)的一個子集getTechList(),這提供了AND與OR匹配技術(shù),語義。
下面的例子相匹配,可以支持NFCA和NDEF技術(shù)或可以支持NfcB和NDEF技術(shù)代碼:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
</resources>

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcB</tech>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
</resources>

二、讀取數(shù)據(jù)

做了這么多,終于可以在activity里面讀取,寫入nfc了,首先我們定義了NfcScanActivity來掃描nfc設(shè)備

        ......//關(guān)鍵代碼,onCreate中
        // 獲取默認(rèn)的NFC控制器
        mAdapter = NfcAdapter.getDefaultAdapter(this);
        if (mAdapter == null) {
            promt.setText("設(shè)備不支持NFC!");
            return;
        }
        if (!mAdapter.isEnabled()) {
            promt.setText("請在系統(tǒng)設(shè)置中先啟用NFC功能!");
            return;
        }
        //創(chuàng)建intent檢測nfc
        mPendingIntent = PendingIntent
                .getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
      //onResume
      if (this.mAdapter == null)
            return;
        if (!this.mAdapter.isEnabled()) {
            promt.setText("請在系統(tǒng)設(shè)置中先啟用NFC功能!");
        }

         //監(jiān)聽nfc設(shè)備
        this.mAdapter.enableForegroundDispatch(this, this.mPendingIntent, null, null);

因為我們注冊了Intent Filter,當(dāng)掃描到設(shè)備后,系統(tǒng)會調(diào)用我們的app,進(jìn)而會進(jìn)入activity的onNewIntent(Intent paramIntent)方法

@Override
    public void onNewIntent(Intent intent) {
        setIntent(paramIntent);
        //我們接受到消息啦,可以處理了
// 得到是否檢測到TAG觸發(fā)
        if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())
                || NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())
                || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
            // 處理該intent
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            // 獲取標(biāo)簽id數(shù)組
            byte[] bytesId = tag.getId();
            //獲取消息內(nèi)容
            NfcMessageParser nfcMessageParser = new NfcMessageParser(intent);
            List<String> tagMessage = nfcMessageParser.getTagMessage();

            if (tagMessage == null || tagMessage.size() == 0) {

                //Toast.makeText(this, "NFC格式不支持...", Toast.LENGTH_LONG).show();
            } else {
                for (int i = 0; i < tagMessage.size(); i++) {
                    Log.e("tag", tagMessage.get(i));
                }
                datas = tagMessage.get(0);
            }
            String info = "";
            if (datas != null) {
                info += "內(nèi)容:" + datas + "\n卡片ID:" + bytesToHexString(bytesId) + "\n";
            } else {
                info += "內(nèi)容:空" + "\n卡片ID:" + bytesToHexString(bytesId) + "\n";
            }


            String[] techList = tag.getTechList();

            //分析NFC卡的類型: Mifare Classic/UltraLight Info
            String cardType = "";


            for (String aTechList : techList) {
                if (TextUtils.equals(aTechList, "android.nfc.tech.Ndef")) {
                    Ndef ndef = Ndef.get(tag);
                    cardType += "最大數(shù)據(jù)尺寸:" + ndef.getMaxSize() + "字節(jié)";
                }
            }

            info += cardType;

            promt.setText("NFC信息如下:\n" + info);


        }
    }

傳來的intent中包含了:
EXTRA_TAG:一個Tag對象,表示掃描標(biāo)簽。
EXTRA_NDEF_MESSAGES(可選):從標(biāo)簽解析NDEF消息的數(shù)組,這個就是我們要的數(shù)據(jù),顯示到屏幕上。
EXTRA_ID(可選):標(biāo)簽的ID。
處理消息的代碼如下:

// 得到Intent中的NDEF數(shù)據(jù)
    private NdefMessage[] getTagNdef(Intent intent) {
        // TODO Auto-generated method stub
        NdefMessage[] msgs = null;
        Parcelable[] rawMsgs = intent
                .getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);

        //把序列化數(shù)據(jù)轉(zhuǎn)成Messaeg對象
        if (rawMsgs != null) {
            msgs = new NdefMessage[rawMsgs.length];
            for (int i = 0; i < rawMsgs.length; i++) {
                msgs[i] = (NdefMessage) rawMsgs[i];
            }
        } else {
            // Unknown tag type
            byte[] empty = new byte[]{};
            NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN, empty,
                    empty, empty);
            NdefMessage msg = new NdefMessage(new NdefRecord[]{record});
            msgs = new NdefMessage[]{msg};
        }
        return msgs;
    }
     // 把Message轉(zhuǎn)成List
    private List<String> getNdefString(NdefMessage[] msgs) {
        // TODO Auto-generated method stub
        if (msgs != null && msgs.length != 0) {
            List<String> tagMessage = parser(msgs[0]);
            return tagMessage;
        }
        return null;
    }

然后就可以顯示到你想要的地方去了

三、寫入數(shù)據(jù)

寫入數(shù)據(jù)最關(guān)鍵的就是創(chuàng)建一個NdefRecord對象,然后通過Ndef對象的writeNdefMessage(NdefMessage message)方法寫入,當(dāng)然前提還是要檢測到設(shè)備,這里格式是TNF_WELL_KNOWN with RTD_TEXT,即寫入文本字符串,如果你想寫入其他數(shù)據(jù),請參考官方文檔

/**
     * 創(chuàng)建record,格式為TNF_WELL_KNOWN with RTD_TEXT
     *
     * @param payload      你要寫入的數(shù)據(jù)
     * @param locale
     * @param encodeInUtf8 編碼
     * @return
     */
public NdefRecord createTextRecord(String payload, 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 = payload.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);
    NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
    NdefRecord.RTD_TEXT, new byte[0], data);
    return record;
}

生成需要的NdefMessage對象

     //textRecord就是上面生成的NdefRecord
    NdefMessage message = new NdefMessage(new NdefRecord[]{textRecord});

最后寫入數(shù)據(jù):

/**
     * 寫入數(shù)據(jù)
     * @param message
     * @param tag  intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
     * @return
     */
    boolean writeTag(NdefMessage message, Tag tag) {
        int size = message.toByteArray().length;
        try {
            //鏈接nfc
            Ndef ndef = Ndef.get(tag);
            if (ndef != null) {
                ndef.connect();
                if (!ndef.isWritable()) {
Toast.makeText(this, "tag不允許寫入", Toast.LENGTH_SHORT).show();
                 
                    return false;
                }
                if (ndef.getMaxSize() < size) {
Toast.makeText(this,"文件大小超出容量", Toast.LENGTH_SHORT).show();
                 
                    return false;
                }

                ndef.writeNdefMessage(message);
Toast.makeText(this,"寫入數(shù)據(jù)成功.", Toast.LENGTH_SHORT).show();
           
                isWrite = false;
                finish();
                return true;
            } else {
                NdefFormatable format = NdefFormatable.get(tag);
                if (format != null) {
                    try {
                        format.connect();
                        format.format(message);
                        Toast.makeText(this,"格式化tag并且寫入message", Toast.LENGTH_SHORT).show();
                      
                        return true;
                    } catch (IOException e) {
                            Toast.makeText(this, "格式化tag失敗.", Toast.LENGTH_SHORT).show();
                      
                        return false;
                    }
                } else {
                        Toast.makeText(this, "Tag不支持NDEF", Toast.LENGTH_SHORT).show();
               
                    return false;
                }
            }
        } catch (Exception e) {
                Toast.makeText(this,"寫入數(shù)據(jù)失敗", Toast.LENGTH_SHORT).show();
          
        }

        return false;
    }

完整代碼已上傳至github,歡迎clone,謝謝star

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容