Android下NFC的简单使用

现在很多手机已经配备了NFC(Near Field Communication 近场通信)的功能,我就为此专门研究过,可以到本文末尾下载源代码。

Android官方资料:http://developer.android.com/guide/topics/connectivity/nfc/index.html

相关资料参考:http://blog.csdn.net/nicebooks/article/details/6223956

相关Android应用:https://play.google.com/store/apps/details?id=com.nxp.nfc.tagwriter

关于NFC的知识就不讲了,下面直接看代码,主要是读取、写入的功能。先自己新建一个Android工程,下面是用到的变量:

    private NfcAdapter mNfcAdapter;//NFC适配器,就是那个NFC读卡器
    PendingIntent mNfcPendingIntent;//用于截获系统Intent,因为系统检测到NFC卡片时会选择程序去响应
    IntentFilter[] mWriteTagFilters;//IntentFilter表示满足本程序响应的条件
    private boolean mWriteMode = false;//控制读写模式切换

还是建议看看官方资料,这样才能明白某些函数的意思。接下来,在onCreate函数里检测NFC:

        //获取默认NFC设备
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (mNfcAdapter == null) {
            Toast.makeText(this, "该设备不支持NFC!", Toast.LENGTH_LONG).show();
            finish();
            return;
        }

        //查看NFC是否开启
        if (!mNfcAdapter.isEnabled()){
            Toast.makeText(this, "请在系统设置中先启用NFC功能", Toast.LENGTH_LONG).show();
            finish();
            return;
        }

        mNfcPendingIntent = PendingIntent.getActivity(this, 0,
                new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
        IntentFilter ndefDetected = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        try {
            ndefDetected.addDataType("text/plain");
        } catch (MalformedMimeTypeException e) {
            e.printStackTrace();
        }
        mWriteTagFilters = new IntentFilter[] { ndefDetected };

这里先检测手机是否支持NFC,finish()表示退出程序。最后,给上面变量赋值,添加截获的NFC数据类型为"text/plain",表示纯文本。

所以,如果NFC卡片存的是URL地址,我们的程序将无法截获,系统会用浏览器打开。当我们按下Home键,这时就无需截获系统Intent了,添加如下代码:

    @Override
    protected void onResume()
    {
        super.onResume();
        mNfcAdapter.enableForegroundDispatch(this, mNfcPendingIntent, mWriteTagFilters, null);
    }

    @Override
    protected void onPause()
    {
        super.onPause();
        mNfcAdapter.disableForegroundNdefPush(this);
    }

手机发现了NFC Tag,如果我们已经添加了PendingIntent,并且满足我们的IntentFilter条件,就会触发一个如下事件:

    //必须的函数,截获系统itent,然后触发读取和写入操作
    @Override
    protected void onNewIntent(Intent intent)
    {
        if (!mWriteMode && NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
        {
            NdefMessage[] msgs = getNdefMessages(intent);
            String body = new String(msgs[0].getRecords()[0].getPayload());

            System.out.println("***读取数据***" + body);
            tagInfo.setText(body);
        }

        if (mWriteMode && NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
        {
            Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            boolean writesuccess = writeTag(getNoteAsNdef(), detectedTag);
            System.out.println("***写入数据***");
            if (writesuccess){
                Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show();
            }
            else{
                Toast.makeText(this, "写入失败!", Toast.LENGTH_SHORT).show();
            }
        }
    }

系统检测到Tag时,会将其所有信息封装到Intent中,我们截获了它就可以读取了。如果要写入,需要构造NdefMessage信息才行。

上面代码中的getNoteAsNdef用来根据输入构造NdefMessage:

    //从输入框获取信息,然后构造NdefMessage用于写入
    private NdefMessage getNoteAsNdef()
    {
        byte[] textBytes = (inputText.getText().toString()).getBytes();
        NdefRecord textRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA, "text/plain".getBytes(), new byte[] {}, textBytes);
        return new NdefMessage(new NdefRecord[] { textRecord });
    }

实际读取数据部分如下:

    //实际读取数据部分
    private NdefMessage[] getNdefMessages(Intent intent)
    {
        NdefMessage[] msgs = null;
        String action = intent.getAction();
        if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action))
        {
            Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
            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 };
            }
        } else
        {
            // Log.d(TAG, "Unknown intent.");
            finish();
        }
        return msgs;
    }

实际写入部分如下:

    //实际写入数据部分
    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())
                {
                    System.out.println("Tag is read-only.");
                    return false;
                }
                if (ndef.getMaxSize() < size)
                {
                    System.out.println("Tag capacity is " + ndef.getMaxSize() + " bytes, message is " + size + " bytes.");
                    return false;
                }

                ndef.writeNdefMessage(message);
                System.out.println("****写入数据成功***");

                return true;
            } else
            {
                NdefFormatable format = NdefFormatable.get(tag);
                if (format != null)
                {
                    try
                    {
                        format.connect();
                        format.format(message);
                        System.out.println("**Formatted tag and wrote message**");
                        return true;
                    } catch (IOException e)
                    {
                        System.out.println("==Failed to format tag.==");
                        return false;
                    }
                } else
                {
                    System.out.println("Tag doesn't support NDEF.");
                    return false;
                }
            }
        } catch (Exception e)
        {
            System.out.println("!!写入数据失败!!");
        }
        return false;
    }

上面的写入、读取部分都不是很简洁,因为要兼容到android 2.3(API 10)的版本,Android 4.0以上提供了比较简单的读写方式,可以参考下面的文章:

http://shanetully.com/2012/12/writing-custom-data-to-nfc-tags-with-android-example/

如果你需要这样的功能,比如检测到文本时便启动你的程序,你可以在配置文件里设置,查看官方文档即可,我这里没有这样的需求。

最后,打开AndroidManifest.xml文件,添加如下代码用于开启NFC权限。注意,我的源代码

    <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="14" />
    <uses-permission android:name="android.permission.NFC" />
上一篇:Android开发之“点9”


下一篇:Linux下vi编辑器粘贴复制剪切功能