关于FNC的识别。

Android设备支持,读写数据,还有写入特定的URI后让设备识别后进行操作。


Android对NFC的支持

不同的NFC标签之间差异很大,有的只支持简单的读写操作,有时还会采用支持一次性写入的芯片,将NFC标签设计成只读的。当然,也存在一些复杂的NFC标签,例如,有一些NFC标签可以通过硬件加密的方式限制对某一区域的访问。还有一些标签自带操作环境,允许NFC设备与这些标签进行更复杂的交互。这些标签中的数据也会采用不同的格式。但Android SDK API主要支持NFC论坛标准(Forum Standard),这种标准被称为NDEF(NFC Data Exchange Format,NFC数据交换格式)。

NDEF格式其实就类似于硬盘的NTFS,下面我们看一下NDEF数据:

(1)NDEF数据的操作

Android SDK API支持如下3种NDEF数据的操作:

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

用于描述NDEF格式数据的两个类:

1)NdefMessage:描述NDEF格式的信息,实际上我们写入NFC标签的就是NdefMessage对象。
2)NdefRecord:描述NDEF信息的一个信息段,一个NdefMessage可能包含一个或者多个NdefRecord。

NdefMessage和NdefRecord是Android NFC技术的核心类,无论读写NDEF格式的NFC标签,还是通过Android Beam技术传递Ndef格式的数据,都需要这两个类。

(2)非NDEF数据的操作

对于某些特殊需求,可能要存任意的数据,对于这些数据,我们就需要自定义格式。这些数据格式实际上就是普通的字节流,至于字节流中的数据代表什么,就由开发人员自己定义了。




也就是说,NFC中的数据是以NDEF与非NDEF数据存储用于识别的。非NEDF为开发着定制识别,NEDF为统一识别。



)编写NFC程序的基本步骤

1)设置权限,限制Android版本、安装的设备:


<!--要求当前设备的最小版本-->


<uses-sdk android:minSdkVersion="14"/>
<!-- 给予当前设备FNC权限 -->


2)定义可接收Tag的Activity

Activity清单需要配置一下launchMode属性:

<!--启动模式,一定注意不可以是standard-->

<activity
    android:name=".TagTextActivity"
    android:launchMode="singleTop"/>



直接上代码。

package com.zq.sensoradapter;

import android.app.PendingIntent;
 
import android.content.Intent;
 
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.os.Build;
import android.os.Parcelable;
 
import android.support.annotation.RequiresApi;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
 
import java.util.Arrays;

 

public class  MainActivity extends AppCompatActivity {

    public static final  String TAG = "NFC";


    private NfcAdapter mNfcAdapter;//FNC的适配器
    private PendingIntent pendingIntent;//准备启动

    @RequiresApi(api = Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_nfc);

        Button button = findViewById(R.id.sure_btn);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            recognize = true;
            }
        });
    }

    private boolean recognize = false;//是否识别

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

    }

    private String mTagText; //我的标签字符
    /**
     * 读取nfc的数据
     */
    private void readNfcText(Intent intent) {
        //1.获取Tag对象
        Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        //2.获取Ndef的实例
        Ndef ndef = Ndef.get(detectedTag);
        mTagText = ndef.getType() + "\nmaxsize:" + ndef.getMaxSize() + "bytes\n\n";
        readNfcTag(intent);
        Log.e(TAG,"mtagNfc= " + mTagText);
    }

    /**
     * 读取NFC标签文本数据
     */
    private void readNfcTag(Intent intent) {
        if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) {
            Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
                    NfcAdapter.EXTRA_NDEF_MESSAGES);
            NdefMessage msgs[] = null;
            int contentSize = 0;
            if (rawMsgs != null) {
                msgs = new NdefMessage[rawMsgs.length];
                for (int i = 0; i < rawMsgs.length; i++) {
                    msgs[i] = (NdefMessage) rawMsgs[i];
                    contentSize += msgs[i].toByteArray().length;
                }
            }
            try {
                if (msgs != null) {
                    NdefRecord record = msgs[0].getRecords()[0];
                    String textRecord = parseTextRecord(record);//解密写入的文本
                    mTagText += "textRecord:" + textRecord +
                            "\ntext\n" + contentSize + " bytes";
                }
            } catch (Exception e) {
            }
        }
    }
    /**
     * 解析NDEF文本数据,从第三个字节开始,后面的文本数据
     * @param ndefRecord
     * @return
     */
    public static String parseTextRecord(NdefRecord ndefRecord) {
        /**
         * 判断数据是否为NDEF格式
         */
        //判断TNF
        if (ndefRecord.getTnf() != NdefRecord.TNF_WELL_KNOWN) {
            return null;
        }
        //判断可变的长度的类型
        if (!Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) {
            return null;
        }
        try {
            //获得字节数组,然后进行分析
            byte[] payload = ndefRecord.getPayload();
            //下面开始NDEF文本数据第一个字节,状态字节
            //判断文本是基于UTF-8还是UTF-16的,取第一个字节"位与"上16进制的80,16进制的80也就是最高位是1,
            //其他位都是0,所以进行"位与"运算后就会保留最高位
            String textEncoding = ((payload[0] & 0x80) == 0) ? "UTF-8" : "UTF-16";
            //3f最高两位是0,第六位是1,所以进行"位与"运算后获得第六位
            int languageCodeLength = payload[0] & 0x3f;
            //下面开始NDEF文本数据第二个字节,语言编码
            //获得语言编码
            String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII");
            //下面开始NDEF文本数据后面的字节,解析出文本
            String textRecord = new String(payload, languageCodeLength + 1,
                    payload.length - languageCodeLength - 1, textEncoding);
            return textRecord;
        } catch (Exception e) {
            throw new IllegalArgumentException();
        }
    }

    @Override
    protected void onStart() {
        super.onStart();
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        //一旦截获NFC消息,就会通过PendingIntent调用窗口
        pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0);
    }

    @Override
    protected void onResume() {
        super.onResume();
        mNfcAdapter.enableForegroundDispatch(this, pendingIntent, null, null);
    }


    @Override
    protected void onPause() {
        super.onPause();
        //恢复默认状态
        if (mNfcAdapter != null){
            mNfcAdapter.disableForegroundDispatch(this);
    }
    }


}



这样就是识别的过程,详细的配合大家自己的需求去实现。

主要是理解NEDF这个是什么,然后再NFC相应的时候如何去调用,与基本的配置。

这里主要是读取数据,详细的写入与识别特定的URI可点入原文链接。

本文引用