Android NfcManager 之NFC接入与介绍

NFC:全称是近场通信(Near Field Communication),是一种短距离无线技术

Android Beam是一个基于近场通信所做的新功能,这个功能可以为其他手机分享你正在使用的功能。 Android升级到4.1后,Android Beam现在可以在两台支持NFC的Android设备间分享照片和视频,还可以与支持NFC的蓝牙设备相连。

Android NFC同时支持三个主要的操作模式:

1.设备读/写模式,允许NFC设备的读/写NFC目标设备;

2.P2P模式,使NFC设备与其他NFC节点交换数据;这种运作模式被使用在Android Beam中;

3/卡仿真模式,使NFC设备本身作为一个NFC卡。然后模拟NFC卡可以通过一个外部的NFC读写访问,如销售终端NFC点。

4.NDEF数据

从NFC便签读取NDEF格式的数据
向NFC标签写入NDEF格式的数据
通过Android Beam技术将NDEF数据发送到另一部NFC设备

5.NFC的三重过滤机制intent-filter

两个终端设备要想读写数据,会有个短暂配对的时间,数据接收端会根据具体的数据格式和标签类型调用相应的Activity(Tag Dispatch),这个activity需要定义一个intent filter中指定不同的过滤机制,分三个等级,所以叫NFC的三重过滤机制

5.1NDEF_DISCOVERED

只过滤固定格式的NDEF数据,比如纯文本,指定协议(HTTP FTP SMB等)的URI

5.2TECH_DISCOVERED

当ACTION_NDEF_DISCOVERED指定的过滤机制无法匹配Tag时,就会使用这种过滤机制进行匹配,这种过滤机制并不是通过Tag的数据进行匹配的,而是根据Tag支持的数据存储格式进行匹配,因此这种机制使用范围很广

5.3TAG_DISCOVERED

这种机制用来处理未识别的Tag

接入流程:

1.首选NFC依赖硬件,这个就需要权限支持

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

外获取NFC设备数据需要在<activity/>内添加如下内容

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

nfc_tech_filter是在res/xml文件下的自定义xml文件:

<?xml version="1.0" encoding="utf-8"?>

<resources>
    <tech-list>
        <tech>android.nfc.tech.IsoDep</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
    </tech-list>
</resources>

2.三种模式的Demo运行

NFC的数据NfcAdapter来管理的,NfcAdapter有两种途径获取

NfcManager manager=(NfcManager)getSystemService(Context.NFC_SERVICE);
NfcAdapter adapter=  manager.getDefaultAdapter();

这是通过NFCmanager获取,

NfcManger的构造器 也是通过NcfAdapter.getNfcAdapter(Context)获取adapter的实例。

同理:我们也可以直接获取NfcAdapter,不通过NfcManger来获取。

NcfAdapter adapter=NfcAdapter.getDefaultAdapter(Context context)

 这个adapter其实也是需要通过NfcManager来获取,直接调用静态方法,针对不熟悉getSystemService来说,可以直接使用封装现成的。

adapter的内部会有一个:

static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class

,所以NFC是独立于Activity,因为adapter内部有一个静态变量,会把当前山下文使用的nfcadapter缓存起来。

2.Tag接收页面的启动模式

<activity
    android:name=".nfc.NfcHomeActivity"
    android:label="NFC主业"
    android:configChanges="screenSize"
    android:launchMode="singleTask"
    android:immersive="true"
    tools:ignore="Instantiatable">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />

        <category android:name="android.intent.category.LAUNCHER" />

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

launchMode:因为NFC是一个独立特性,所有页面启动需要保持一个,singleTask或者

singleTop

NdefMessage:

主要是描写叙述NDEF格式的信息


NdefRecord:

这个是秒速NDEF信息的一个信息段

这两个都是Android NCF技术的核心类,不管是读写NFC标签还是通过Android Beam技术传递数据都须要这两个类

小牛刀


1.获取Tag对象

Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

正常该intent通过Activity这个方法获取:

protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    
}

因为任何页面被打开多少次,都会执行onNewIntent方法

2.推断NFC标签的数格式

Ndef ndef = Ndef.get(tag);

3.写入数据

ndef.wrriteNdefMessage(ndefMessage);

4.NdefRecord:NDEF格式数据,创建对象提供如下


public static NdefRecord createApplicationRecord(String packageName)

public static NdefRecord createUri(Uri uri)

public static NdefRecord createUri(String uriString)

public static NdefRecord createMime(String mimeType, byte[] mimeData)

public static NdefRecord createExternal(String domain, String type, byte[] data) 

public static NdefRecord createTextRecord(String languageCode, String text) 

public NdefRecord(short tnf, byte[] type, byte[] id, byte[] payload)

public NdefRecord(byte[] data)
Uri支持格式如下:
private static final String[] URI_PREFIX_MAP = new String[] {
        "", // 0x00
        "http://www.", // 0x01
        "https://www.", // 0x02
        "http://", // 0x03
        "https://", // 0x04
        "tel:", // 0x05
        "mailto:", // 0x06
        "ftp://anonymous:anonymous@", // 0x07
        "ftp://ftp.", // 0x08
        "ftps://", // 0x09
        "sftp://", // 0x0A
        "smb://", // 0x0B
        "nfs://", // 0x0C
        "ftp://", // 0x0D
        "dav://", // 0x0E
        "news:", // 0x0F
        "telnet://", // 0x10
        "imap:", // 0x11
        "rtsp://", // 0x12
        "urn:", // 0x13
        "pop:", // 0x14
        "sip:", // 0x15
        "sips:", // 0x16
        "tftp:", // 0x17
        "btspp://", // 0x18
        "btl2cap://", // 0x19
        "btgoep://", // 0x1A
        "tcpobex://", // 0x1B
        "irdaobex://", // 0x1C
        "file://", // 0x1D
        "urn:epc:id:", // 0x1E
        "urn:epc:tag:", // 0x1F
        "urn:epc:pat:", // 0x20
        "urn:epc:raw:", // 0x21
        "urn:epc:", // 0x22
        "urn:nfc:", // 0x23
};

三、核心业务

1.action的校验

        String action = intent.getAction();
        if (TextUtils.equals(action, NfcAdapter.ACTION_TAG_DISCOVERED)) {

            return true;
        }

2.读
 

private void readNfcTag(Intent intent) {
    if (intent == null)
        return;
    Parcelable[] parcelables = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
    if (parcelables == null || parcelables.length == 0)
        return;
    NdefMessage mNdefMsg = (NdefMessage) parcelables[0];
    NdefRecord mNdefRecord = mNdefMsg.getRecords()[0];
    if (mNdefRecord != null) {

        try {
            String msg = new String(mNdefRecord.getPayload(), "utf-8");

        } catch (Exception e) {

        }

    }


}

3.写

    //NFC写入
    private void writeNFC(Tag tag) {
        //null不执行操作,强调敲代码的逻辑性
        if (tag == null) {
            return;
        }

        NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]{NdefRecord.createApplicationRecord(mPackNmae)});

        //获得写入大小
        int size = ndefMessage.toByteArray().length;
        //2.推断是否是NDEF标签
        try {
            Ndef ndef = Ndef.get(tag);
            if (ndef != null) {
                //说明是NDEF标签,開始连接
                ndef.connect();
                //推断是否可写
                if (!ndef.isWritable()) {
                    showToast("当前设备不支持写入");
                    return;
                }
                //推断大小
                if (ndef.getMaxSize() < size) {
                    showToast("容量太小了");
                    return;
                }
                //写入
                ndef.writeNdefMessage(ndefMessage);

                showToast("写入成功");

            }
        } catch (Exception e) {
            e.printStackTrace();

        }
    }

加密卡芯片的读写MifareClassic

MifareClassic:

“MIFARE Classic是恩智浦半导体开发的可用于非接触式智能卡,符合ISO/IEC 14443 A类标准。用于公共交通票证等应用,还可用于各类其他应用有S20,S50(M1),S70几种规格,主要是根据存储器容量划分,存储器容量分别有320B,1K,4K

这种卡和其他的不同,是有密码校验,不同厂家可以定制不同的密码和数据格式,简单的介绍如下


        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        MifareClassic mifareClassic = MifareClassic.get(tag);
        try {
            boolean connected = mifareClassic.isConnected();
            if (connected) {
                int count = mifareClassic.getSectorCount();

                for (int index = 0; index < count; index++) {
                    //获取善区数

                    boolean keyAopen = mifareClassic.authenticateSectorWithKeyA(index, MifareClassic.KEY_DEFAULT);
                    if (keyAopen) {
                        //获取扇区里面块的数量
                        int bCount = mifareClassic.getBlockCountInSector(index);
                        int bIndex = mifareClassic.sectorToBlock(index);
                        for (int position = 0; position < bCount; position++) {
                            byte[] data = mifareClassic.readBlock(bIndex + position);//进行了读卡
                            msgBuffer.append("块" + (bIndex + position) + "数据:").append(ByteArrayToHexString(data)).append("\r\n");

                            //修改KeyA和KeyB
                            if ((bIndex + position) == (4 * index + 3)) {
                                //将所有扇区的最后一个Block修改为111111111111ff078069111111111111
                                mifareClassic.writeBlock(bIndex + position, new byte[]{(byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0xff, 0x07, (byte) 0x80, (byte) 0x69, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11, (byte) 0x11});
//                                Log.e("onNewIntent:",(bIndex+position)+"块加密成功");

                            }


                        }

                    }


                }

            }

        } catch (Exception e) {

        }

关于Mifare Classic也是用的比较多的地方,暂时先写到这,以后将会整理一份详细的介绍。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值