NFC的应用

懵懂的女人 提交于 2019-12-07 11:30:18

NFC和RFID

RFID是射频识别技术,它主要是通过无线电讯号识别特定目标,并可读写数据,但仅仅是单向的读取。
RFID有低频(几mm的传输距离)、高频(13.56Mhz)、超高频(防碰撞算法、低功耗芯片设计、UHF电子标签天线设计、测试认证)、微波频段等,频段不同,导致功率不同,导致传输的距离不同。
NFC是近距离无线通讯技术,芯片具有相互通信能力,并有计算能力。NFC可以看作是RFID的子集,用的是RFID的高频(13.56MHz)的标准,但却是双向过程。
他们的区别基于两点。
首先,NFC技术增加了点对点通信功能,可以快速建立蓝牙设备之间的无线通信.NFC设备彼此寻
找对方进而建立通信连接。在通信模式上,NFC不同于RFID网络,后者是建立于主从关系之下,并且芯片以被动的方式通过昂贵的、需要能源支持的“读取”设备来读取。而NFC设备却能被设置为被动和主动两种模式,即使在设备关机的情况下(被动模式),仍然可以发送识别数据,也正是这一特点使其成为智能卡应用的理想选择。同时,它也可在主动模式下,与其他主动或被动的RFID设
备进行通信。
其次,NFC和RFID针对的应用不同,除了点对点通信的应用之外,NFC的主要应用是移动小额支付。NFC的应用针对移动性的特点,用于识别和数据交换,而RFID的主要用途是识别。

什么是NFC?

近距离无线通信技术(Near Field Communication,NFC)。
NFC提供了一种简单的、非触控式的解决方案,可以让消费者简单直观地交换信息、访问内容与服务。与wifi、蓝牙、红外线等数据传输技术的一个主要差异就是有效距离一般不能超过4cm。

NFC标签是什么?

其实就是一个小小的可以擦写输入的小芯片,我们可以将一些个性化的功能写进去。NFC标签怎么用呢?就是带有NFC芯片的手机通过扫描NFC标签,可以立刻响应标签里的功能,比如最简单的开启飞行模式。

14443A标签卡

MifareClass:
标准卡

MifareUltralight:
这类卡相对较小,不加密,成本也低,只有几百字节大小。

15693标签卡

NfcV
8字节UID,最后一字节固定为0xE0,需要发送写的命令串才能读。
命令列表,命令格式:标识 + 命令 + 参数 + 数据 + 校验

ISO10536,ISO15693,ISO14443的区别

ISO10536标准主要发展于1992到1995年间,由于这种卡的成本高,与接触式IC卡相比优点很少,因此这种卡从未在市场上销售。

ISO14443和ISO15693标准在1995年开始操作,单个系统于1999年进入市场,两项标准的完成则是在2000年之后。二者皆以13.56MHz交变信号为载波频率:ISO15693读写距离较远,当然这也与应用系统的天线形状和发射功率有关;而ISO 14443 读写距离稍近,但应用较广泛,目前的第二代电子身份证采用的标准是ISO 14443 TYPE B协议。
  ISO14443定义了TYPE A、TYPE B两种类型协议。通信速率为106kbits/s,它们的不同主要在于载波的调制深度及位的编码方式。
  4443B和15693最大的区别可能是他们的读写速度14443B一般是106Kb/s及以上,而15693一般上限是53或者26.5Kb/s,用通讯速率换取读取范围,使得他们的应用有很大不同
还有很多其他的区别,如防冲突机制、信源信道编码方式、通讯协议等等
MF RC531不能读取ISO15693,如果单纯的读取ISO15693,可以选择SL RC400

The minimum operating field strength(最低工作场强)is specified:
ISO14443:Hmin= 1.5 A/m(Mifare)
ISO15693: Hmin = 0.15 A/m(I*Code)

也就是说,ISO15693标准的灵敏度是ISO14443的10倍,这应该是主要区别之一。

是说15693的距离更远一些,
14443更成熟,加密性更好用在保密性更好的地方
15693是开放的

https://blog.csdn.net/obanaganastar/article/details/51491105

NFC支持3种工作模式

1.读卡器模式;

2.仿真卡模式;

3.点对点模式;

1.读卡器模式:

通过NFC设备(支持NFC的Android手机)从带有NFC芯片的标签、贴纸、报纸、明信片等媒介读取信息,或将数据写到这些媒介中。

2.仿真卡模式:

是将支持NFC的手机或其他电子设备当成借记卡、信用卡、公交卡、门禁卡等IC卡使用;基本原理是将相应的IC卡中的信息(支付凭证)封装成数据包存储在支持NFC的手机中,在使用时还需要一个NFC射频器(相当于刷传统IC卡时使用的刷卡器),将手机靠近NFC射频器,手机就会收到NFC射频器发过来的信号,在通过一系列复杂的验证后,将IC卡的相应信息传入NFC射频器,最后这些IC卡数据会传入NFC射频器连接的计算机,并进行相应的处理(如电子转账、开门等操作)。

3.点对点模式:

与蓝牙、红外差不多,可以用于不同的NFC设备之间进行数据交换,只是NFC的点对点模式有效距离更短,不能超过4cm;但是如果两个设备使用的都是Android4.2及以上版本,NFC会直接利用蓝牙传输,这种技术被称为Android Beam,所以Android Beam传输数据的两部设备不局限于4cm之内。

基础知识

  • Android SDK API主要支持NFC论坛标准(Forum Standard),这种标准被称为NDEF(NFC Data Exchange Format,NFC数据交换格式);
  • Android SDK API支持如下三种NDEF数据的操作:
    a.从NFC标签读取NDEF格式的数据;
    b.向NFC标签写入NDEF格式的数据;
    c.通过Android Beam技术将NDEF数据发送到另一部NFC设备;
  • 在一个NFC设备读取NFC标签或另一个NFC设备中的数据之前会在0.1秒的时间之内建立NFC连接,然后数据会自动从被读取一端流向读取数据的一端;数据接收端会根据具体的数据格式和标签类型调用相应的Activity(这种行为也称为Tag Dispatch),这些Activity都需要定义Intent Filter,这些Intent Filter中就会指定不同的过滤机制,分为三个级别,也称为NFC的三重过滤机制。
    a.NDEF_DISCOVERED:
    只过滤固定格式的NDEF数据。例如:纯文本、指定协议(http、ftp、smb等)的URI等;
    b.TECH_DISCOVERED:
    当ACTION_NDEF_DISCOVERED指定的过滤机制无法匹配Tag时,就会使用这种过滤机制进行匹配,这种过滤机制并不是通过Tag中的数据格式进行匹配的,而是根据Tag支持的数据存储格式进行匹配,因此这种过滤机制的范围更广;
    c. TAG_DISCOVERED:
    如果将NFC过滤机制看成if…else if…else语句的话,那么这种过滤机制就相当于else部分,当前面两种过滤机制都匹配失败后,系统就会利用这种过滤机制来处理,这种过滤机制用来处理未识别的Tag(数据格式不对,而且Tag支持的格式也不匹配)。
  • Android系统会依次匹配NDEF_DISCOVERED、TECH_DISCOVERED和TAG_DISCOVERED;如果通过三重过滤机制仍然无法匹配Tag,则什么都不做;通常在成功匹配Tag后,Android设备会发出比较清脆的声音,而未成功匹配Tag,就会发出比较沉闷的声音。

在这里插入图片描述

Android中的NFC

  • 获取NFC权限
<uses-permission android:name="android.permission.NFC" />
  • 获取默认的NFC控制器,并进行判断
private static NfcAdapter nfcAdapter;//NFC适配器
...
   ...
   nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (nfcAdapter == null) {
            Log.d("h_bl", "No support NFC!");
            Toast.makeText(getApplicationContext(), "No support NFC!", Toast.LENGTH_SHORT).show();

            return;
        }
        if (!nfcAdapter.isEnabled()) {
            Toast.makeText(getApplicationContext(), "Please enable the NFC function first in the system settings!", Toast.LENGTH_SHORT).show();
            Log.d("h_bl", "请在系统设置中先启用NFC功能!");
        }
  • 捕获NFC Intent
mIntent = this.getIntent();
  • 在onCreate()方法中,创建一个PendingIntent对象
// NFC前台调度系统
    private PendingIntent pendingIntent = null;
...
......
// 初始化PendingIntent,当有NFC设备连接上的时候,就交给当前Activity处理
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
  • onPause(),onResume(),onNewIntent()方法中添加如下代码
@Override
    protected void onPause() {
        if (nfcAdapter != null)
            nfcAdapter.disableForegroundDispatch(this);
        super.onPause();
    }

    @Override
    protected void onResume() {
        if (nfcAdapter != null)
            nfcAdapter.enableForegroundDispatch(this, pendingIntent, filters, tenchlists);
        super.onResume();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        // 当前app正在前端界面运行,这个时候有intent发送过来,那么系统就会调用onNewIntent回调方法,将intent传送过来
        // 我们只需要在这里检验这个intent是否是NFC相关的intent,如果是,就调用处理方法
        Log.d("h_bl", "onNewIntent");
        praseIntent(intent);  //处理Intent
    }
  • 关键步骤:onResume()函数中有两个参数还未补充:filters和techLists,在onCreate()中声明
public String[][] tenchlists;
    public IntentFilter[] filters;
    ...
    .......
        // 声明前台activity能处理的NFC标签技术的数组
        tenchlists = new String[][] { { IsoDep.class.getName() }, { NfcV.class.getName() }, { NfcF.class.getName() }, };
        // 前台activity过滤获得所有的ACTION_TECH_DISCOVERED的intent
        try {
            filters = new IntentFilter[] { new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED, "*/*") };
        } catch (MalformedMimeTypeException e1) {
            e1.printStackTrace();

主要代码

  • UUIDActivity
package com.example.yjw.NFC;

import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.IsoDep;
import android.nfc.tech.MifareClassic;
import android.nfc.tech.MifareUltralight;
import android.nfc.tech.NfcA;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.example.yjw.NFC.mifare.StringUtils;
import com.example.yjw.myviewpager.R;

import java.util.ArrayList;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * NFC-A,B  NFC卡片读取
 */
public class UUIDActivity extends AppCompatActivity {
    @BindView(R.id.listview)
    ListView listview;
    private Intent mIntent = null;
    private static NfcAdapter nfcAdapter;
    private static PendingIntent mPendingIntent;
    private static IntentFilter[] mFilters;
    private static String[][] mTechLists;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_uuid);
        ButterKnife.bind(this);

        //获取默认的NFC控制器,并进行判断
        nfcAdapter = NfcAdapter.getDefaultAdapter(this);
        if (nfcAdapter == null) {
            Log.d("h_bl", "No support NFC!");
            Toast.makeText(getApplicationContext(), "No support NFC!", Toast.LENGTH_SHORT).show();

            return;
        }
        if (!nfcAdapter.isEnabled()) {
            Toast.makeText(getApplicationContext(), "Please enable the NFC function first in the system settings!", Toast.LENGTH_SHORT).show();
            Log.d("h_bl", "请在系统设置中先启用NFC功能!");
        }

        //启用一个PendingIntent
        /*mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
                getClass()), 0);*/
        mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);


        //intent匹配NfcAdapter的活动
        // 前台activity过滤获得所有的ACTION_TECH_DISCOVERED的intent
        IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
        try {
            ndef.addDataType("*/*");
        } catch (IntentFilter.MalformedMimeTypeException e) {
            throw new RuntimeException("fail", e);
        }
        mFilters = new IntentFilter[]{ndef};

        //设置IsoDep,MifareClassic,MifareUltralight
        // 声明前台activity能处理的NFC标签技术的数组
        mTechLists = new String[][]{new String[]{IsoDep.class.getName()},
                new String[]{MifareUltralight.class.getName()}, new String[]{MifareClassic.class.getName()}};


        //捕获NFC Intent
        mIntent = this.getIntent();

        ReadCardSN();
    }

    private void ReadCardSN() {
        // 解析该Intent的Action
        String action = mIntent.getAction();

        if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)) {//当前的action
            //获取标签tag
            Tag tag = mIntent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

            //获取NFC卡的唯一值
            byte[] bytCardSN = tag.getId();
            String strCardSN = StringUtils.bytesToHexString(bytCardSN);
            //调用getTechList()方法来确定该tag能支持的技术
            String[] arTeachList = tag.getTechList();

            NfcA nfcA = NfcA.get(tag);

            byte[] bytAtqa = nfcA.getAtqa();
            short Sak = nfcA.getSak();
            int maxTranLen = nfcA.getMaxTransceiveLength();

            String strAtqa = StringUtils.bytesToHexString(bytAtqa);
            String strSAK = String.format("%02X", Sak);
            String strCardType;
            if (Sak == 0x08) {
                strCardType = "M1 card";
            } else if (Sak == 0x20) {
                strCardType = "CPU card";
            } else if (Sak == 0x28 || Sak == 0x38) {
                strCardType = "Composite card";
            } else {
                strCardType = "Unknown type";
            }

            ArrayList<String> blockData = new ArrayList<>();
            blockData.add("NFC卡唯一值");
            blockData.add(">" + strCardSN);
            blockData.add("提供的功能");
            for (int i = 0; i < arTeachList.length; i++) {
                String strTeach = arTeachList[i];

                blockData.add(">" + strTeach);
            }
            blockData.add("ATQA");
            blockData.add(">" + strAtqa);

            blockData.add("SAK");
            blockData.add(">" + strSAK + " " + strCardType);

            blockData.add("Max transmission length");
            blockData.add(">" + maxTranLen);
            //---------------------显示输出---------------------
            String[] contents = new String[blockData.size()];
            blockData.toArray(contents);
            listview.setAdapter(new ArrayAdapter<String>(this,
                    android.R.layout.simple_list_item_1, contents));
        } else {
            showAlert("Do not find card");
        }
    }

    /**
     * 显示对话框
     *
     * @param alertCase
     */
    private void showAlert(String alertCase) {
        // prepare the alert box
        AlertDialog.Builder alertbox = new AlertDialog.Builder(this);

        alertbox.setMessage(alertCase);
        // set a positive/yes button and create a listener
        alertbox.setPositiveButton("OK", new DialogInterface.OnClickListener() {

            // Save the data from the UI to the database - already done
            public void onClick(DialogInterface arg0, int arg1) {
                //clearFields();
            }
        });
        // display box
        alertbox.show();
    }

    @Override
    protected void onPause() {
        if (nfcAdapter != null)
            nfcAdapter.disableForegroundDispatch(this);
        super.onPause();
    }

    @Override
    protected void onResume() {
        //mFilters,前台调度系统activity能过滤的nfc标签,重写能调度的nfc标签过滤器,或者总是填null。
        //mTechLists,应用程序希望处理的NFC标签技术的数组
        //如果filters和techLists参数均为空,则会导致前台activity通过ACTION_TAG_DISCOVERED intent接收所有的标签。
        if (nfcAdapter != null)
            //-----------------非常关键,必要的哦,不能删除----------------
            nfcAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters,
                    mTechLists);
        super.onResume();
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        // 当前app正在前端界面运行,这个时候有intent发送过来,那么系统就会调用onNewIntent回调方法,将intent传送过来
        // 我们只需要在这里检验这个intent是否是NFC相关的intent,如果是,就调用处理方法
        Log.d("h_bl", "onNewIntent");
        mIntent = intent;
        ReadCardSN();  //处理Intent
    }
}

  • StringUtils
package com.example.yjw.NFC.mifare;

/**
 * Created by Administrator on 2018/7/26.
 */

public class StringUtils {

    /*
    byte[] --> 16 hex string
     */
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        char[] buffer = new char[2];
        for (int i = 0; i < src.length; i++) {
            buffer[0] = Character.forDigit((src[i] >>> 4) & 0x0F, 16);
            buffer[1] = Character.forDigit(src[i] & 0x0F, 16);
            System.out.println(buffer);
            stringBuilder.append(buffer);
        }
        return stringBuilder.toString();
    }

/*
  16 hex string--->byte[]
 */
    public static byte[] hexStringToByte(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    private static int toByte(char c) {
        byte b = (byte) "0123456789ABCDEF".indexOf(c);
        return b;
    }
}

  • activity_uuid.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical"
    tools:context="com.example.yjw.NFC.UUIDActivity">



    <ListView
        android:id="@+id/listview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"></ListView>

</LinearLayout>

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!