Android NFC(二)

上一篇中,简单的介绍了下nfc的相关知识,这一篇将以代码的形式更深入的理解nfc。

一、准备工作

首先肯定要申请相应的权限:
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
同时要注意最小api的版本,根据谷歌官方的说话,NFC在Android上,也是从API9才开始支持的,但是到了API14 Google才对NFC大力开发,所以等到了API15的时候,NFC的传输速度就得到了很大的加强,所以最小api最好设置为14.
<uses-sdk android:minSdkVersion="14"/>
然后在相应的要接收nfc信息的activity中注册intent filter:

            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
                <data android:mimeType="text/plain"/>
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED"/>
            </intent-filter>

            <meta-data
                android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter"/>
            <intent-filter>
                <action android:name="android.nfc.action.TAG_DISCOVERED"/>
                <category android:name="android.intent.category.DEFAULT"/>
            </intent-filter>

如果您的活动过滤器是ACTION_TECH_DISCOVERED,你必须创建一个指定的活动支持内技术的XML资源文件,可以通过android.nfc.Tag类的getTechList()获取子集
其中名为nfc_tech_filter的xml文件如下:

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

当然您也可以指定多个tech-list组。每个的tech-list集独立地考虑,并且您的活动被认为是一个匹配,如果任何一个 tech-list组是由返回的技术的一个子集getTechList(),这提供了AND与OR匹配技术,语义。
下面的例子相匹配,可以支持NFCA和NDEF技术或可以支持NfcB和NDEF技术代码:

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
</resources>

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.NfcB</tech>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
</resources>

二、读取数据

做了这么多,终于可以在activity里面读取,写入nfc了,首先我们定义了NfcScanActivity来扫描nfc设备

        ......//关键代码,onCreate中
        // 获取默认的NFC控制器
        mAdapter = NfcAdapter.getDefaultAdapter(this);
        if (mAdapter == null) {
            promt.setText("设备不支持NFC!");
            return;
        }
        if (!mAdapter.isEnabled()) {
            promt.setText("请在系统设置中先启用NFC功能!");
            return;
        }
        //创建intent检测nfc
        mPendingIntent = PendingIntent
                .getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
      //onResume
      if (this.mAdapter == null)
            return;
        if (!this.mAdapter.isEnabled()) {
            promt.setText("请在系统设置中先启用NFC功能!");
        }

         //监听nfc设备
        this.mAdapter.enableForegroundDispatch(this, this.mPendingIntent, null, null);

因为我们注册了Intent Filter,当扫描到设备后,系统会调用我们的app,进而会进入activity的onNewIntent(Intent paramIntent)方法

@Override
    public void onNewIntent(Intent intent) {
        setIntent(paramIntent);
        //我们接受到消息啦,可以处理了
// 得到是否检测到TAG触发
        if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())
                || NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())
                || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
            // 处理该intent
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            // 获取标签id数组
            byte[] bytesId = tag.getId();
            //获取消息内容
            NfcMessageParser nfcMessageParser = new NfcMessageParser(intent);
            List<String> tagMessage = nfcMessageParser.getTagMessage();

            if (tagMessage == null || tagMessage.size() == 0) {

                //Toast.makeText(this, "NFC格式不支持...", Toast.LENGTH_LONG).show();
            } else {
                for (int i = 0; i < tagMessage.size(); i++) {
                    Log.e("tag", tagMessage.get(i));
                }
                datas = tagMessage.get(0);
            }
            String info = "";
            if (datas != null) {
                info += "内容:" + datas + "\n卡片ID:" + bytesToHexString(bytesId) + "\n";
            } else {
                info += "内容:空" + "\n卡片ID:" + bytesToHexString(bytesId) + "\n";
            }


            String[] techList = tag.getTechList();

            //分析NFC卡的类型: Mifare Classic/UltraLight Info
            String cardType = "";


            for (String aTechList : techList) {
                if (TextUtils.equals(aTechList, "android.nfc.tech.Ndef")) {
                    Ndef ndef = Ndef.get(tag);
                    cardType += "最大数据尺寸:" + ndef.getMaxSize() + "字节";
                }
            }

            info += cardType;

            promt.setText("NFC信息如下:\n" + info);


        }
    }

传来的intent中包含了:
EXTRA_TAG:一个Tag对象,表示扫描标签。
EXTRA_NDEF_MESSAGES(可选):从标签解析NDEF消息的数组,这个就是我们要的数据,显示到屏幕上。
EXTRA_ID(可选):标签的ID。
处理消息的代码如下:

// 得到Intent中的NDEF数据
    private NdefMessage[] getTagNdef(Intent intent) {
        // TODO Auto-generated method stub
        NdefMessage[] msgs = null;
        Parcelable[] rawMsgs = intent
                .getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);

        //把序列化数据转成Messaeg对象
        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};
        }
        return msgs;
    }
     // 把Message转成List
    private List<String> getNdefString(NdefMessage[] msgs) {
        // TODO Auto-generated method stub
        if (msgs != null && msgs.length != 0) {
            List<String> tagMessage = parser(msgs[0]);
            return tagMessage;
        }
        return null;
    }

然后就可以显示到你想要的地方去了

三、写入数据

写入数据最关键的就是创建一个NdefRecord对象,然后通过Ndef对象的writeNdefMessage(NdefMessage message)方法写入,当然前提还是要检测到设备,这里格式是TNF_WELL_KNOWN with RTD_TEXT,即写入文本字符串,如果你想写入其他数据,请参考官方文档

/**
     * 创建record,格式为TNF_WELL_KNOWN with RTD_TEXT
     *
     * @param payload      你要写入的数据
     * @param locale
     * @param encodeInUtf8 编码
     * @return
     */
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {
    byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII"));
    Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");
    byte[] textBytes = payload.getBytes(utfEncoding);
    int utfBit = encodeInUtf8 ? 0 : (1 << 7);
    char status = (char) (utfBit + langBytes.length);
    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);
    NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
    NdefRecord.RTD_TEXT, new byte[0], data);
    return record;
}

生成需要的NdefMessage对象

     //textRecord就是上面生成的NdefRecord
    NdefMessage message = new NdefMessage(new NdefRecord[]{textRecord});

最后写入数据:

/**
     * 写入数据
     * @param message
     * @param tag  intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
     * @return
     */
    boolean writeTag(NdefMessage message, Tag tag) {
        int size = message.toByteArray().length;
        try {
            //链接nfc
            Ndef ndef = Ndef.get(tag);
            if (ndef != null) {
                ndef.connect();
                if (!ndef.isWritable()) {
Toast.makeText(this, "tag不允许写入", Toast.LENGTH_SHORT).show();
                 
                    return false;
                }
                if (ndef.getMaxSize() < size) {
Toast.makeText(this,"文件大小超出容量", Toast.LENGTH_SHORT).show();
                 
                    return false;
                }

                ndef.writeNdefMessage(message);
Toast.makeText(this,"写入数据成功.", Toast.LENGTH_SHORT).show();
           
                isWrite = false;
                finish();
                return true;
            } else {
                NdefFormatable format = NdefFormatable.get(tag);
                if (format != null) {
                    try {
                        format.connect();
                        format.format(message);
                        Toast.makeText(this,"格式化tag并且写入message", Toast.LENGTH_SHORT).show();
                      
                        return true;
                    } catch (IOException e) {
                            Toast.makeText(this, "格式化tag失败.", Toast.LENGTH_SHORT).show();
                      
                        return false;
                    }
                } else {
                        Toast.makeText(this, "Tag不支持NDEF", Toast.LENGTH_SHORT).show();
               
                    return false;
                }
            }
        } catch (Exception e) {
                Toast.makeText(this,"写入数据失败", Toast.LENGTH_SHORT).show();
          
        }

        return false;
    }

完整代码已上传至github,欢迎clone,谢谢star

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

推荐阅读更多精彩内容

  • NFC 基础 本文档介绍了在Android上的基本的NFC任务。它说明了如何发送和接收的NDEF消息(NDEF m...
    张云飞Vir阅读 3,205评论 0 52
  • NFC 基础 本文档介绍了在Android上的基本的NFC任务。它说明了如何发送和接收的NDEF消息(NDEF m...
    张云飞Vir阅读 8,656评论 2 53
  • 一:NFC的tag分发系统如果想让android设备感应到NFC标签,你要保证两点1:屏幕没有锁住2:NFC功能已...
    巧士周瑜阅读 2,655评论 0 5
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,914评论 25 707
  • 大多数时的你是快乐的 这让我感到安心 可这些快乐都与我无关 我又开始矫情 你是我梦里的风 在梦里也抓不住你 你走 ...
    王老七阅读 170评论 0 0