• android nfc中Ndef格式的读写


    版权声明:本文为博主原创文章,未经博主同意不得转载。

    https://blog.csdn.net/qilixiang012/article/details/24743791

    检測到标签后在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() + "
    最大数据容量:" + ndef.getMaxSize()
                    + " bytes
    
    ";
            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() + "
    最大数据容量:" + ndef.getMaxSize()
                    + " bytes
    
    ";
            //读取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() + "
    
    纯文本
    "
                                + 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() + "
    最大数据容量:" + ndef.getMaxSize()
                    + " bytes
    
    ";
            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() + "
    
    Uri
    "
                            + 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(" ") + 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,中间用“
    ”分离
            for (PackageInfo packageInfo : packageInfos) {
                //LoadLabel方法返回的值就是定义Activity时的android:label属性值
                mPackages.add(packageInfo.applicationInfo.loadLabel(packageManager)
                        + "
    " + 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

  • 相关阅读:
    Javascript DMO 编程艺术
    PHPExcel
    MYSQL
    AJAX全接触
    正则表达式
    常用知识
    PHP 常用函数
    thinkphp5 公共函数的使用与调用
    thinkphp 使用phpExcel 导入和导出
    php 判断是pc端还是移动端
  • 原文地址:https://www.cnblogs.com/mqxnongmin/p/10681784.html
Copyright © 2020-2023  润新知