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

文件配置
要实现前台分发功能,首先需要配置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:写的不好,仅为记录

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容