美文网首页
NFC标签前台分发及数据读写

NFC标签前台分发及数据读写

作者: 遇见_未见 | 来源:发表于2017-02-28 11:05 被阅读188次

文件配置
要实现前台分发功能,首先需要配置Manifest文件,其中LanchActivity只是一个简单的启动页面,跳转到MainActivity(这才是要处理NFC标签的页面)。按官方的文档,处理标签扫描结果的Activity就是程序的启动页面,但是我们一般不会在启动页面处理数据。

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

    <uses-feature
        android:name="android.hardware.nfc"
        android:required="true"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">

            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>
            <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
                       android:resource="@xml/nfc_tech_filter"/>
        </activity>
        <activity android:name=".LanchActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>

@xml/nfc_tech_filter文件,该文件中是应用程序支持的NFC技术列表

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.MifareClassic</tech>
    </tech-list>

</resources>

官网文档支持的所有技术列表如下(我们只需要是其子集即可):

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

根据官网说明,标签分发拦截有以下步骤:
1、在onCreate方法中创建全局的PendingIntent对象,以便扫描到NFC标签时系统可以用扫描到的tag信息填充该pendingIntent对象。代码如下:

 pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);

2、定义你要拦截的intent过滤器。当设备扫描到一个标签时,系统前台分发系统根据收到的intent来校验是否符合我们指定的intentFilter。如果匹配,应用程序将会处理该intent,否则,调用系统intent分发系统。如果指定intent过滤器和技术过滤数组为空,你将会接收到TAG_DISCOVERED上的所有标记。(即,如果要拦截系统标签分发系统到我们前台Activity,需要定义拦截的intent过滤器、我们要处理的技术过滤数组)
系统示例代码如下:

IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
    try {
        ndef.addDataType("*/*");    /* Handles all MIME based dispatches.
                                       You should specify only the ones that you need. */
    }
    catch (MalformedMimeTypeException e) {
        throw new RuntimeException("fail", e);
    }
   intentFiltersArray = new IntentFilter[] {ndef, };

在我测试的过程中,没有用到mime类型:

techListsArray = new String[][]{new String[]{MifareClassic.class.getName()}};//支持的技术类别
IntentFilter ndef = new IntentFilter();
ndef.addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);//要过滤的标签级别
intentFiltersArray = new IntentFilter[]{ndef};

3、覆写系统方法

  @Override
    protected void onNewIntent(Intent intent) {
        processIntent(intent);//处理返回数据的方法,扫描到的标签数据都在intent中
    }

    @Override
    protected void onPause() {
        super.onPause();
        nfcAdapter.disableForegroundDispatch(this);
    }

    @Override
    protected void onResume() {
        super.onResume();
        nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
        if (getIntent().getAction() != null) {
            if (NfcAdapter.ACTION_TECH_DISCOVERED.endsWith(getIntent().getAction())) {
                processIntent(getIntent());
            }
        }
    }

其中,onResume方法中的if判断是为了当程序未运行时扫描到NFC标签也可以接收到数据。

然后重要的是数据读写,这里只是简单的操作,具体还是要参考官方文档:

  //读取所有block中的数据
  private void readData(final MifareClassic mfc) {
        if (mfc != null) {
            if (mfc.isConnected()) {
                try {
                    String result = "";
                    tvStatus.setText("正在读取数据");
                    for (int i = 0; i < mfc.getSectorCount(); i++) {//循环读取所有的扇区
                        int bindex;
                        int bCount;
                        if (mfc.authenticateSectorWithKeyA(i, MifareClassic.KEY_DEFAULT)) {//读取的时候要校验key,否则无法读取
                            bindex = mfc.sectorToBlock(i);
                            bCount = mfc.getBlockCountInSector(i);
                            result += "Sector " + i + "验证成功\n";
                            for (int j = 0; j < bCount; j++) {//循环读取指定扇区所有的块,每个扇区最后一个块是该块的key,除非要加密,否则不要轻易改变
                                byte[] data = mfc.readBlock(bindex);
                                result += "Block " + bindex + " : " + new String(data, Charset.forName("UTF-8")) + "\n";
                                bindex++;
                            }
                        }
                    }
                    tvStatus.setText("数据读取完成");
                    tvReadData.setText(result);
                } catch (Exception ex) {
                    tvStatus.setText("读取失败:" + ex.getMessage());
                }
            }
        } else {
            Toast.makeText(this, "未扫描到NFC", Toast.LENGTH_SHORT).show();
        }
    }

    //向标签指定block写入数据
    private void writeData(final MifareClassic mfc, final int blockIndex, String msg) {
        if (mfc != null) {
            try {
                Log.e(TAG, "writeData: isConnected:" + mfc.isConnected());
                if (mfc.isConnected()) {
                    byte[] temp = msg.getBytes(Charset.forName("UTF-8"));
                    final byte[] write = new byte[MifareClassic.BLOCK_SIZE];//每一块最大存储字节数
                    for (int i = 0; i < MifareClassic.BLOCK_SIZE; i++) {
                        if (i < temp.length)
                            write[i] = temp[i];
                        else
                            write[i] = 0;
                    }
                    tvStatus.setText("正在写入");
                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Log.e(TAG, "run: 写入内容:" + new String(write));
                                mfc.writeBlock(blockIndex, write);//写入方法是一个阻塞函数,不能在UI线程调用
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        tvStatus.setText("写入完成");
                                    }
                                });
                            } catch (final Exception ex) {
                                Log.e(TAG, "writeData_Ex: " + ex.getMessage());
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        tvStatus.setText("写入失败:" + ex.getMessage());
                                    }
                                });
                            }
                        }
                    }).start();
                } else {
                    Toast.makeText(this, "NFC连接断开", Toast.LENGTH_SHORT).show();
                }
            } catch (Exception ex) {
                Log.e(TAG, "writeData: " + ex.getMessage());
            }
        } else {
            Toast.makeText(this, "未扫描到NFC卡片", Toast.LENGTH_SHORT).show();
        }
    }

NFCWRDemo
PS:写的不好,仅为记录

相关文章

网友评论

      本文标题:NFC标签前台分发及数据读写

      本文链接:https://www.haomeiwen.com/subject/viqxgttx.html