NFC通信

引言

NFC,即Near Field Communication,近距离无线通讯技术,是一种短距离的(通常<=4cm或更短)高频(13.56M Hz)无线通信技术,它提供了一种简单、触控式的解决方案,可以让消费者简单直观地交换信息、访问内容与服务。NFC技术是由非接触式射频识别(RFID)及互连互通技术整合演变而来,通过在单一芯片上集成感应式读卡器、感应式卡片和点对点通信的功能,利用移动终端实现移动支付、电子票务、门禁、移动身份识别、防伪等应用。

NFC技术

工作模式

NFC根据业务模式不同大概分为三种模式。
(1)读卡器模式
  数据在NFC芯片中,可以简单理解成“刷标签”。本质上就是通过支持NFC的手机或其它电子设备从带有NFC芯片的标签、贴纸、名片等媒介中读写信息。通常NFC标签是不需要外部供电的。当支持NFC的外设向NFC读写数据时,它会发送某种磁场,而这个磁场会自动的向NFC标签供电。
(2)仿真卡模式
  数据在支持NFC的手机或其它电子设备中,可以简单理解成“刷手机”。本质上就是将支持NFC的手机或其它电子设备当成借记卡、公交卡、门禁卡等IC卡使用。基本原理是将相应IC卡中的信息凭证封装成数据包存储在支持NFC的外设中 。
在使用时还需要一个NFC射频器(相当于刷卡器)。将手机靠近NFC射频器,手机就会接收到NFC射频器发过来的信号,在通过一系列复杂的验证后,将IC卡的相应信息传入NFC射频器,最后这些IC卡数据会传入NFC射频器连接的电脑,并进行相应的处理(如电子转帐、开门等操作)。
(3)点对点模式
  该模式与蓝牙、红外差不多,用于不同NFC设备之间进行数据交换,不过这个模式已经没有有“刷”的感觉了。其有效距离一般不能超过4厘米,但传输建立速度要比红外和蓝牙技术快很多,传输速度比红外块得多,如过双方都使用Android4.2,NFC会直接利用蓝牙传输。这种技术被称为Android Beam。所以使用Android Beam传输数据的两部设备不再限于4厘米之内。
  点对点模式的典型应用是两部支持NFC的手机或平板电脑实现数据的点对点传输,例如,交换图片或同步设备联系人。因此,通过NFC,多个设备如数字相机,计算机,手机之间,都可以快速连接,并交换资料或者服务。

重要参数

  1. 有效传输范围<=4cm
  2. 传输速度有三种:106kbps; 212kbps; 424kbps
  3. 建立连接时间<1s
  4. NFC工作频率为13.65兆赫兹

开发流程

NFC标签的复杂度不一。简单的标签仅能够提供读写语义,有时编程域是一次性的,写完卡片就变成只读。更复杂一点的tag能够提供数学运算,拥有加密硬件保护区块的访问。最最复杂的tag包含操作环境,允许tag上执行的代码进行交互。我们还能够以各种格式来向tag中写入存储数据,但很多Android的API框架都是基于NFC论坛制定的NDEF标准。

添加NFC权限

首先,在AndroidManifests.xml中声明NFC和添加相应的权限。

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

添加识别NFC标签

NFC有三种过滤器分别是ACTION_NDEF_DISCOVERED,ACTION_TECH_DISCOVERED,ACTION_TAG_DISCOVERED。

  1. ACTION_NDEF_DISCOVERED

当扫描到的tag中包含有NDEF载荷且为已知类型,该intent将用来启动Activity。该intent的优先级最高,tag分发系统总是先于其他intent用该intent来启动Activity。

  1. ACTION_TECH_DISCOVERED

如果manifest中没有注册处理ACTION_NDEF_DISCOVERED类型的intent,该intent将被用以启动Activity。如果tag中没有包含可以映射到MIME或者URI类型的数据,或者虽然没有包含NDEF数据,但是已知的tag技术,则该intent也会被直接启用。

  1. ACTION_TAG_DISCOVERED

如果没有上述两个intent,那么该intent就会启动。

当android设备扫描到一个NFC标签时,会自动寻找最适合的Activity来处理这个Tag。在Activity中添加intent-filter标签,当扫描到NFC设备时系统会打开此Activity。

1.ACTION_NDEF_DISCOVERED过滤器定义如下:


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

2.ACTION_TECH_DISCOVERED过滤器定义如下:

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

filter_nfc.xml文件

<?xml version="1.0" encoding="utf-8" ?>
 <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-list>
      <tech-list>
        <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>

MIFARE Classic数据格式就是NfcA,MIFARE DESFire数据格式是IsoDep(交通卡),NfcB(身份证),Felica用的就是NfcF,德州仪器的VicinityCard卡用的是NfcV,而Android分享文件就是实用的Ndef格式传输数据。

3.ACTION_TAG_DISCOVERED过滤器定义如下:

<intent-filter>
    <action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>

初始化适配器

NFC开发需要使用安卓系统提供的NfcAdapter对象,使用该对象管理NFC设备。

//获取NfcAdapter对象,此方法与获取蓝牙适配器对象类似
 mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
        if (mNfcAdapter == null) {
            Toast.makeText(this, "该设备不支持nfc", Toast.LENGTH_SHORT).show();
            finish();
            return;
        }
        if (!mNfcAdapter.isEnabled()) {
            startActivity(new Intent("android.settings.NFC_SETTINGS"));
            Toast.makeText(this, "设备未开启nfc", Toast.LENGTH_SHORT).show();
        }

启用NFC前台调度

在Activity的onResume方法中打开前台调度。

@Override
    protected void onResume() {
        super.onResume();
        //一旦截获NFC消息,就会通过PendingIntent调用窗口
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
        IntentFilter[] intentFilters = new IntentFilter[]{};
        //用于打开前台调度(拥有最高的权限),当这个Activity位于前台(前台进程),即可调用这个方法开启前台调度
        mNfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFilters, null);
    }

接收数据

当手机端检测接收到NFC设备数据时,在onNewIntent方法中即可接受到数据。在onNewIntent方法参数intent对象中获取数据。

@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())
                || NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())
                || NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction())) {
            Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
            //读取NFC的id
            String id = ByteArrayToHexString(tag.getId());

            //获取tag中的数据信息
            String[] tagTechList = tag.getTechList();
            if (tagTechList != null) {
                for (int i = 0; i < tagTechList.length; i++) {
                    stringBuilder.append("*").append(tagTechList[i]).append("*").append("\n");
                    stringBuilder.append(readTech(tag, tagTechList[i],intent));
                }
            }
            Parcelable[] rawArray = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);  
            if (rawArray != null) {
                //获取NDEF描述信息
                NdefMessage mNdefMsg = (NdefMessage) rawArray[0];
                //获取NDEF记录信息
                NdefRecord mNdefRecord = mNdefMsg.getRecords()[0];
                if (mNdefRecord != null) {
                    String readResult = new String(mNdefRecord.getPayload(), "UTF-8");
                }
            }
        }
    }

发送数据

* 向NFC发送数据
* data要发送的数据
* intent onNewIntent方法回调的Intent对象

public static void writeNFCToTag(String data, Intent intent) throws IOException, FormatException {
        //获取Tag对象
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        Ndef ndef = Ndef.get(tag);
        //连接
        ndef.connect();
        NdefRecord ndefRecord = null;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
            ndefRecord = NdefRecord.createTextRecord(null, data);
        }
        //数据格式打包
        NdefRecord[] records = {ndefRecord};
        NdefMessage ndefMessage = new NdefMessage(records);
        //发送数据
        ndef.writeNdefMessage(ndefMessage);
}

关闭NFC前台调度

之前在Activity的onResume方法中启用NFC的前台调度,相应的,在onPuse方法中关闭NFC的前台调度。

//调用disableForegroundDispatch方法关闭前台调度
if(mNfcAdapter != null){
     mNfcAdapter.disableForegroundDispatch(this);
}

总结

NFC技术作为一种新兴技术在世界范围内受到了广泛关注,尤其是手机的广泛应用,为NFC技术的长足发展提供了前提。NFC技术原理简单,因此成本相对低廉,除此之外NFC通信的带宽高、能耗低等特点也是促进NFC技术发展的一大优势。

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

推荐阅读更多精彩内容