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信息結構


 Supported TNFs and their mappings:

Type Name Format (TNF) Mapping
TNF_ABSOLUTE_URI URI based on the type field.
TNF_EMPTY Falls back to ACTION_TECH_DISCOVERED.
TNF_EXTERNAL_TYPE URI based on the URN in the type field. The URN is encoded into the NDEF type field in a shortened form: <domain_name>:<service_name>. Android maps this to a URI in the form: vnd.android.nfc://ext/<domain_name>:<service_name>.
TNF_MIME_MEDIA MIME type based on the type field.
TNF_UNCHANGED Invalid in the first record, so falls back to ACTION_TECH_DISCOVERED.
TNF_UNKNOWN Falls back to ACTION_TECH_DISCOVERED.
TNF_WELL_KNOWN MIME type or URI depending on the Record Type Definition (RTD), which you set in the type field. See Table 2. for more information on available RTDs and their mappings.
Supported RTDs for TNF_WELL_KNOWN and their mappings:

Record Type Definition (RTD) Mapping
RTD_ALTERNATIVE_CARRIER Falls back to ACTION_TECH_DISCOVERED.
RTD_HANDOVER_CARRIER Falls back to ACTION_TECH_DISCOVERED.
RTD_HANDOVER_REQUEST Falls back to ACTION_TECH_DISCOVERED.
RTD_HANDOVER_SELECT Falls back to ACTION_TECH_DISCOVERED.
RTD_SMART_POSTER URI based on parsing the payload.
RTD_TEXT MIME type of text/plain.
RTD_URI URI based on payload.

說明:讀取TNF的類型后(能夠是上面第一張表中的類型),假設是TNF_WELL_KNOWN時。就能夠獲取RTD(相應格式良好的

{TNF_WELL_KNOWN}的標簽的類型,能夠是第二張表中的類型)


NdefRecord中的經常用法

1.可通過NdefRecord.getTnf()方法來獲得TNF字段。

相應上圖中Header中的Length

2.通過NdefRecord.getType()方法來獲得RTD字段,當TNF為TNF_WELL_KNOWN時的RTD。

相應上圖中Header中的Type

3.通過NdefRecord.getPayload()方法來獲得實際讀寫的數據。

相應上圖中的Payload

Header中的Identifier相應每個Record唯一的Id



NDEF文本格式

NdefMessage中的paylaod就是實際的數據,當中NDEF文本格式為:



NDEF Uri格式

1、NdefMessage中的paylaod就是實際的數據,當中NDEF文本格式為:


2、前綴須要查表解析


Android應用程序記錄Android Application Records(AAR)

1、在Android4.0中引入應用程序記錄(AAR)。當掃描到寫入AAR的NFC標簽時,啟動相應的應用程序。


2、AAR有嵌入到NdefRecord內部的應用程序包名。Android會針對AAR來搜索整個NdefMessage,假設找到一個AAR。就會基於AAR內部的包名來啟動應用程序。

3、NFC標簽調度系統對包括AAR標簽的調度:

1.若跟Intent匹配的Activity也跟AAR匹配,則啟動該Activity。

2.若跟Intent匹配。而跟AAR不匹配。則啟動AAR指定的應用程序。

3.假設沒有跟AAR相應的應用程序,則啟動各種市場來下載相應基於AAR的應用程序。


Android應用程序記錄創建方法

1、調用NdefRecord類的creatApplicationRecord()方法來創建應用程序記錄。

2、將所創建的AAR嵌入到NdefMessage中。
NdefMessage msg = new NdefMessage(new Ndefrecord[]{…,NdefRecord. creatApplicationRecord(“com.example.android.beam”)})

3、除非AAR是你NdefMessage中的唯一記錄。否則不要將AAR嵌入到NdefMessage的第一條記錄。



NDEF for Text 讀寫,樣例程序:

ReadWriteTextMainActivity:

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);

    }

    //單擊“輸入要寫入文本”button運行的方法
    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:
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:
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:
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);
        }
    }
}
AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="mobile.android.read.write.text"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="15" />

    <uses-permission android:name="android.permission.NFC" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".ReadWriteTextMainActivity"
            android:label="讀寫NFC標簽的純文本數據"
            android:launchMode="singleTask" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
            </intent-filter>
        </activity>
        <activity
            android:name=".ShowNFCTagContentActivity"
            android:label="顯示NFC標簽內容"
            android:launchMode="singleTask" />
        <activity
            android:name=".InputTextActivity"
            android:label="向NFC標簽寫入文本" />
    </application>
</manifest>

NDEF for URL 讀寫。樣例程序:

ReadWriteUriMainActivity:

package mobile.android.read.write.uri;

import mobile.android.read.write.uri.library.UriRecord;
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 ReadWriteUriMainActivity extends Activity {
    private TextView mSelectUri;

    private String   mUri;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_read_write_uri_main);
        mSelectUri = (TextView) findViewById(R.id.textview_uri);

    }

    public void onClick_SelectUri(View view) {
        Intent intent = new Intent(this, UriListActivity.class);
        startActivityForResult(intent, 1);

    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == 1 && resultCode == 1) {
            mUri = data.getStringExtra("uri");
            mSelectUri.setText(mUri);
        }
    }

    @Override
    public void onNewIntent(Intent intent) {
        if (mUri == null) {
            Intent myIntent = new Intent(this, ShowNFCTagContentActivity.class);
            myIntent.putExtras(intent);
            myIntent.setAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
            startActivity(myIntent);
        } else {
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            NdefMessage ndefMessage = new NdefMessage(
                    new NdefRecord[] {createUriRecord(mUri)});

            if (writeTag(ndefMessage, tag)) {
                mUri = null;
                mSelectUri.setText("");
            }

        }

    }

    public NdefRecord createUriRecord(String uriStr) {

        byte prefix = 0;
        //從uri前綴集合中找到匹配的前綴,並獲得相應的標識代碼
        for (Byte b : UriRecord.URI_PREFIX_MAP.keySet()) {
            //將Uri前綴轉換成小寫
            String prefixStr = UriRecord.URI_PREFIX_MAP.get(b).toLowerCase();
            //前綴不為空串
            if ("".equals(prefixStr))
                continue;
            //比較Uri前綴
            if (uriStr.toLowerCase().startsWith(prefixStr)) {
                //用字節表示的Uri前綴
                prefix = b;
                //截取完整Uri中除了Uri前綴外的其它部分
                uriStr = uriStr.substring(prefixStr.length());
                break;
            }
        }
        //為存儲在標簽中的Uri創建一個Byte數組
        byte[] data = new byte[1 + uriStr.length()];
        //指定第1字節為Uri前綴的標識代碼
        data[0] = prefix;
        //將剩余的部分拷貝到data字節數組中
        System.arraycopy(uriStr.getBytes(), 0, data, 1, uriStr.length());
        //創建封裝uri的NdefRecord對象
        NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
                NdefRecord.RTD_URI, new byte[0], data);
        //返回NdefRecord對象
        return record;
    }

    boolean writeTag(NdefMessage message, Tag tag) {
        int size = message.toByteArray().length;

        try {

            Ndef ndef = Ndef.get(tag);
            if (ndef != null) {
                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 format = NdefFormatable.get(tag); if (format != null) { try { 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; } } }

UriListActivity:
package mobile.android.read.write.uri;

import android.app.ListActivity;
import android.content.Intent;
import android.graphics.Camera;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.SimpleAdapter;

public class UriListActivity extends ListActivity implements
        OnItemClickListener {
    private String uris[] = new String[] {"http://www.google.com",
            "http://www.apple.com", "http://developer.apple.com",
            "http://www.126.com", "ftp://192.168.17.160",
            "https://192.168.17.120", "smb://192.168.17.100"};

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, android.R.id.text1, uris);
        setListAdapter(arrayAdapter);
        getListView().setOnItemClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
            long id) {
        Intent intent = new Intent();
        intent.putExtra("uri", uris[position]);
        setResult(1, intent);
        finish();

    }

}
ShowNFCTagContentActivity:
package mobile.android.read.write.uri;

import mobile.android.read.write.uri.library.UriRecord;
import android.app.Activity;
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;

public class ShowNFCTagContentActivity extends Activity {
    private TextView mTagContent;

    private Tag      mDetectedTag;

    private String   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);
        mDetectedTag = getIntent().getParcelableExtra(NfcAdapter.EXTRA_TAG);
        Ndef ndef = Ndef.get(mDetectedTag);
        mTagText = ndef.getType() + "\n最大數據容量:" + ndef.getMaxSize()
                + " bytes\n\n";
        readNFCTag();
        mTagContent.setText(mTagText);
    }

    private void readNFCTag() {

        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {

            Parcelable[] rawMsgs = getIntent().getParcelableArrayExtra(
                    NfcAdapter.EXTRA_NDEF_MESSAGES);

            NdefMessage ndefMessage = null;
            int contentSize = 0;
            if (rawMsgs != null) {

                if (rawMsgs.length > 0) {
                    ndefMessage = (NdefMessage) rawMsgs[0];
                    contentSize = ndefMessage.toByteArray().length;
                } else {
                    return;
                }
            }
            try {

                NdefRecord record = ndefMessage.getRecords()[0];

                UriRecord uriRecord = UriRecord
                        .parse(ndefMessage.getRecords()[0]);

                mTagText += uriRecord.getUri().toString() + "\n\nUri\n"
                        + contentSize + " bytes";

            } catch (Exception e) {
                mTagContent.setText(e.getMessage());
            }
        }

    }
}
UriRecord.java
package mobile.android.read.write.uri.library;

import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import android.net.Uri;
import android.nfc.NdefRecord;

public class UriRecord {
    //映射Uri前綴和相應的值
    public static final Map<Byte, String> URI_PREFIX_MAP = new HashMap<Byte, String>();
    static {
        //設置NDEF Uri規范支持的Uri前綴,在解析payload時,須要依據payload的第1個字節定位相應的uri前綴
        URI_PREFIX_MAP.put((byte) 0x00, "");
        URI_PREFIX_MAP.put((byte) 0x01, "http://www.");
        URI_PREFIX_MAP.put((byte) 0x02, "https://www.");
        URI_PREFIX_MAP.put((byte) 0x03, "http://");
        URI_PREFIX_MAP.put((byte) 0x04, "https://");
        URI_PREFIX_MAP.put((byte) 0x05, "tel:");
        URI_PREFIX_MAP.put((byte) 0x06, "mailto:");
        URI_PREFIX_MAP.put((byte) 0x07, "ftp://anonymous:anonymous@");
        URI_PREFIX_MAP.put((byte) 0x08, "ftp://ftp.");
        URI_PREFIX_MAP.put((byte) 0x09, "ftps://");
        URI_PREFIX_MAP.put((byte) 0x0A, "sftp://");
        URI_PREFIX_MAP.put((byte) 0x0B, "smb://");
        URI_PREFIX_MAP.put((byte) 0x0C, "nfs://");
        URI_PREFIX_MAP.put((byte) 0x0D, "ftp://");
        URI_PREFIX_MAP.put((byte) 0x0E, "dav://");
        URI_PREFIX_MAP.put((byte) 0x0F, "news:");
        URI_PREFIX_MAP.put((byte) 0x10, "telnet://");
        URI_PREFIX_MAP.put((byte) 0x11, "imap:");
        URI_PREFIX_MAP.put((byte) 0x12, "rtsp://");
        URI_PREFIX_MAP.put((byte) 0x13, "urn:");
        URI_PREFIX_MAP.put((byte) 0x14, "pop:");
        URI_PREFIX_MAP.put((byte) 0x15, "sip:");
        URI_PREFIX_MAP.put((byte) 0x16, "sips:");
        URI_PREFIX_MAP.put((byte) 0x17, "tftp:");
        URI_PREFIX_MAP.put((byte) 0x18, "btspp://");
        URI_PREFIX_MAP.put((byte) 0x19, "btl2cap://");
        URI_PREFIX_MAP.put((byte) 0x1A, "btgoep://");
        URI_PREFIX_MAP.put((byte) 0x1B, "tcpobex://");
        URI_PREFIX_MAP.put((byte) 0x1C, "irdaobex://");
        URI_PREFIX_MAP.put((byte) 0x1D, "file://");
        URI_PREFIX_MAP.put((byte) 0x1E, "urn:epc:id:");
        URI_PREFIX_MAP.put((byte) 0x1F, "urn:epc:tag:");
        URI_PREFIX_MAP.put((byte) 0x20, "urn:epc:pat:");
        URI_PREFIX_MAP.put((byte) 0x21, "urn:epc:raw:");
        URI_PREFIX_MAP.put((byte) 0x22, "urn:epc:");
        URI_PREFIX_MAP.put((byte) 0x23, "urn:nfc:");
    }

    private final Uri                     mUri;

    private UriRecord(Uri uri) {
        this.mUri = uri;
    }

    //獲取已經解析的Uri
    public Uri getUri() {
        return mUri;
    }

    public static UriRecord parse(NdefRecord record) {
        //獲取TNF
        short tnf = record.getTnf();
        //TNF是TNF_WELL_KNOWN,使用了前綴的Uri
        if (tnf == NdefRecord.TNF_WELL_KNOWN) {
            return parseWellKnown(record);
        }
        //TNF是TNF_ABSOLUTE_URI。即絕對Uri。不使用前綴
        else if (tnf == NdefRecord.TNF_ABSOLUTE_URI) {
            return parseAbsolute(record);
        }
        throw new IllegalArgumentException("Unknown TNF " + tnf);
    }

    /** Parse and absolute URI record */
    private static UriRecord parseAbsolute(NdefRecord record) {
        //直接將payload轉成uri
        byte[] payload = record.getPayload();
        Uri uri = Uri.parse(new String(payload, Charset.forName("UTF-8")));
        return new UriRecord(uri);
    }

    /** Parse an well known URI record */
    private static UriRecord parseWellKnown(NdefRecord record) {
        //推斷RTD是否為RTD_URI
        if (!Arrays.equals(record.getType(), NdefRecord.RTD_URI))
            return null;
        byte[] payload = record.getPayload();
        /*
         * payload[0] contains the URI Identifier Code, per the NFC Forum
         * "URI Record Type Definition" section 3.2.2.
         * 
         * payload[1]...payload[payload.length - 1] contains the rest of the
         * URI.
         */
        //payload[0]中包括URI標識代碼,也就是URI_PREFIX_MAP中的key
        //依據Uri標識代碼獲取Uri前綴
        String prefix = URI_PREFIX_MAP.get(payload[0]);
        //獲取Uri前綴占用的字節數
        byte[] prefixBytes = prefix.getBytes(Charset.forName("UTF-8"));
        //為容納完整的Uri創建一個byte數組
        byte[] fullUri = new byte[prefixBytes.length + payload.length - 1];
        //將Uri前綴和其余部分組合,形成一個完整的Uri
        System.arraycopy(prefixBytes, 0, fullUri, 0, prefixBytes.length);
        System.arraycopy(payload, 1, fullUri, prefixBytes.length,
                payload.length - 1);
        //依據解析出來的Uri創建Uri對象
        Uri uri = Uri.parse(new String(fullUri, Charset.forName("UTF-8")));
        //創建UriRecord對象並返回
        return new UriRecord(uri);
    }

}
清單文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="mobile.android.read.write.uri"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="15" />

    <uses-permission android:name="android.permission.NFC" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <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>
            <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>
        <activity
            android:name=".ShowNFCTagContentActivity"
            android:label="顯示NFC標簽內容" />
        <activity
            android:name=".UriListActivity"
            android:label="選擇Uri" />
    </application>

</manifest>

AAR樣例程序:

AutoRunApplicationActivity:

package mobile.android.auto.run.application;

import java.net.URI;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.net.Uri;
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.Button;
import android.widget.Toast;

public class AutoRunApplicationActivity extends Activity {
    private Button        mSelectAutoRunApplication;

    private String        mPackageName;

    private NfcAdapter    mNfcAdapter;

    private PendingIntent mPendingIntent;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_auto_run_application);
        mSelectAutoRunApplication = (Button) findViewById(R.id.button_select_auto_run_application);
        //獲得默認的NfcAdapter對象
        mNfcAdapter = mNfcAdapter.getDefaultAdapter(this);
        //創建與當前Activity關聯的PendingIntent對象
        mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
                getClass()), 0);

    }

    //當窗體獲得焦點時會提升當前窗體處理NFC標簽的優先級
    @Override
    public void onResume() {
        super.onResume();
        //提升當前處理NFC標簽的優先級
        if (mNfcAdapter != null)
            mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null,
                    null);
    }

    //當窗體的launchMode被設為singleTop時調用方法(不再調用onCreat方法)
    @Override
    public void onNewIntent(Intent intent) {
        //必須先選擇一個Package
        if (mPackageName == null)
            return;
        //獲取表示當前標簽的對象
        Tag detectedTag = intent.getParcelableExtra(mNfcAdapter.EXTRA_TAG);
        //向標簽寫入Package
        writeNFCTag(detectedTag);
    }

    //當窗體失去焦點后。應恢復Android系統處理NFC標簽的默認狀態
    @Override
    public void onPause() {
        super.onPause();
        //恢復處理NFC標簽的窗體的默認優先級(禁止當前窗體的優先處理NFC標簽)
        if (mNfcAdapter != null)
            mNfcAdapter.disableForegroundDispatch(this);

    }

    //"選擇已安裝的應用程序"button的單擊事件方法
    public void onClick_SelectAutoRunApplication(View view) {
        Intent intent = new Intent(this, InstalledApplicationListActivity.class);
        //顯示“已安裝應用程序”窗體
        startActivityForResult(intent, 0);
    }

    //向標簽寫入數據
    public void writeNFCTag(Tag tag) {
        //必須要指定一個Tag對象
        if (tag == null) {
            Toast.makeText(this, "NFC Tag未建立連接", Toast.LENGTH_LONG).show();
            return;
        }
        //創建NdefMessage對象
        //NdefRecord.creatApplicationRecord方法創建一個封裝Package的NdefRecord對象
        NdefMessage ndefMessage = new NdefMessage(
                new NdefRecord[] {NdefRecord
                        .createApplicationRecord(mPackageName)});
        //獲取NdefMessage對象的尺寸
        int size = ndefMessage.toByteArray().length;

        try {
            //獲取Ndef對象
            Ndef ndef = Ndef.get(tag);
            //處理NDEF格式的數據
            if (ndef != null) {
                //同意對標簽進行IO操作,連接
                ndef.connect();
                //NFC標簽不是可寫的(僅僅讀的)
                if (!ndef.isWritable()) {
                    Toast.makeText(this, "NFC Tag是僅僅讀的。", Toast.LENGTH_LONG)
                            .show();
                    return;
                }
                //NFC標簽的空間不足
                if (ndef.getMaxSize() < size) {
                    Toast.makeText(this, "NFC Tag的空間不足!

", Toast.LENGTH_LONG) .show(); return; } //向NFC標簽寫入數據 ndef.writeNdefMessage(ndefMessage); Toast.makeText(this, "已成功寫入數據!

", Toast.LENGTH_LONG).show(); } else { //創建NdefFormatable對象 NdefFormatable format = NdefFormatable.get(tag); if (format != null) { try { //同意標簽IO操作,進行連接 format.connect(); //又一次格式化NFC標簽。並寫入數據 format.format(ndefMessage); Toast.makeText(this, "已成功寫入數據!", Toast.LENGTH_LONG) .show(); } catch (Exception e) { Toast.makeText(this, "寫入NDEF格式數據失敗!", Toast.LENGTH_LONG) .show(); } } else { Toast.makeText(this, "NFC標簽不支持NDEF格式!", Toast.LENGTH_LONG) .show(); } } } catch (Exception e) { Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); } } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (resultCode == 1) { //更新“選擇已安裝的應用程序”button的顯示文本(Package name和label) mSelectAutoRunApplication.setText(data.getExtras().getString( "package_name")); //以下的代碼用於提取Package Name String temp = mSelectAutoRunApplication.getText().toString(); mPackageName = temp.substring(temp.indexOf("\n") + 1); } } }

InstalledApplicationListActivity:
package mobile.android.auto.run.application;

import java.util.ArrayList;
import java.util.List;
import android.app.ListActivity;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;

public class InstalledApplicationListActivity extends ListActivity implements
        OnItemClickListener {
    //用於保存已安裝應用程序的Package和Label
    private List<String> mPackages = new ArrayList<String>();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //獲得PackageManager對象
        PackageManager packageManager = getPackageManager();
        //獲取系統中已安裝的全部應用程序的信息,每個PackageInfo對象表示一個應用程序
        List<PackageInfo> packageInfos = packageManager
                .getInstalledPackages(PackageManager.GET_ACTIVITIES);
        //枚舉全部的應用程序信息,從中取出Package和應用程序的Label。中間用“\n”分離
        for (PackageInfo packageInfo : packageInfos) {
            //LoadLabel方法返回的值就是定義Activity時的android:label屬性值
            mPackages.add(packageInfo.applicationInfo.loadLabel(packageManager)
                    + "\n" + packageInfo.packageName);
        }
        //創建一個用於操作Package集合的ArrayAdapter對象
        ArrayAdapter<String> arrayAdapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, android.R.id.text1,
                mPackages);
        //在ListView控件中顯示全部的Package和程序名
        setListAdapter(arrayAdapter);
        //指定列表項的單擊事件方法
        getListView().setOnItemClickListener(this);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
            long id) {
        Intent intent = new Intent();
        //當單擊列表項時,會通過package_name傳回Package和Label
        intent.putExtra("package_name", mPackages.get(position));
        setResult(1, intent);
        finish();

    }

}
清單文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="mobile.android.auto.run.application"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="15" />

    <uses-permission android:name="android.permission.NFC" />

    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".AutoRunApplicationActivity"
            android:label="@string/title_activity_auto_run_application"
            android:launchMode="singleTop"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".InstalledApplicationListActivity"
            android:label="@string/title_activity_installed_application_list"
            android:screenOrientation="portrait" />
    </application>

</manifest>

通過瀏覽器自己主動打開一個站點:

package mobile.android.auto.open.uri;

import android.app.Activity;
import android.app.PendingIntent;
import android.content.Intent;
import android.net.Uri;
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.widget.Toast;

public class AutoOpenUriActivity extends Activity {
    private NfcAdapter    nfcAdapter;

    private PendingIntent pendingIntent;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_auto_open_uri);
        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
                getClass()), 0);

    }

    @Override
    public void onResume() {
        super.onResume();
        if (nfcAdapter != null)
            nfcAdapter
                    .enableForegroundDispatch(this, pendingIntent, null, null);
    }

    @Override
    public void onNewIntent(Intent intent) {
        Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        writeNFCTag(detectedTag);
    }

    @Override
    public void onPause() {
        super.onPause();
        if (nfcAdapter != null)
            nfcAdapter.disableForegroundDispatch(this);

    }

    public void writeNFCTag(Tag tag) {
        if (tag == null) {
            Toast.makeText(this, "NFC Tag未建立連接", Toast.LENGTH_LONG).show();
            return;
        }

        // NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]
        // { NdefRecord.createUri("http://blog.csdn.net/nokiaguy")});

        NdefMessage ndefMessage = new NdefMessage(
                new NdefRecord[] {NdefRecord.createUri(Uri
                        .parse("http://www.baidu.com"))});

        int size = ndefMessage.toByteArray().length;

        try {

            Ndef ndef = Ndef.get(tag);
            if (ndef != null) {
                ndef.connect();

                if (!ndef.isWritable()) {
                    Toast.makeText(this, "NFC Tag是僅僅讀的。", Toast.LENGTH_LONG)
                            .show();
                    return;
                }
                if (ndef.getMaxSize() < size) {
                    Toast.makeText(this, "NFC Tag的空間不足!", Toast.LENGTH_LONG)
                            .show();
                    return;
                }

                ndef.writeNdefMessage(ndefMessage);
                Toast.makeText(this, "已成功寫入數據!

", Toast.LENGTH_LONG).show(); } else { NdefFormatable format = NdefFormatable.get(tag); if (format != null) { try { format.connect(); format.format(ndefMessage); Toast.makeText(this, "已成功寫入數據。", Toast.LENGTH_LONG) .show(); } catch (Exception e) { Toast.makeText(this, "寫入NDEF格式數據失敗!", Toast.LENGTH_LONG) .show(); } } else { Toast.makeText(this, "NFC標簽不支持NDEF格式!

", Toast.LENGTH_LONG) .show(); } } } catch (Exception e) { Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show(); } } }




附上官方教程:http://developer.android.com/guide/topics/connectivity/nfc/nfc.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM