NFC的读写卡模式——前台调度系统

来源:互联网 发布:淘宝怎么查看消费记录 编辑:程序博客网 时间:2024/06/06 01:37

接着上一篇文章来说,在前一个文章中,我们为大家简单介绍了一下什么是NFC,在这节内容中,我们为大家介绍一下NFC的读写卡模式的开发。
读写卡模式是通过手机对nfc标签卡信息经行读写操作,但是,在使用前,我们应该去检查一下设置和添加一些权限。
在这里我建议大家将NFC的一些基础操作放入到一个NfcBaseActivity中,这样,我们在使用时就不需要每次都经行重复的操作。
1、检测NFC状态

    public int nfcAdapterInitialize() {//自定义的函数        //尝试去获取设备默认的NfcAdapter(NFC适配器)对象,由于手机中一般只有一个NFC设备,所以我们这里获取默认的即可。        NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);        //判断nfcAdapter是否为空,若为空则手机不支持NFC设备        if (nfcAdapter == null) {            Toast.makeText(this, "不支持nfc", Toast.LENGTH_SHORT).show();            return 0;        } else {//若不为空,则判断NFC是否开启            if (!nfcAdapter.isEnabled()) {                Toast.makeText(this, "nfc没有开启", Toast.LENGTH_SHORT).show();                //我们将跳转到设置页面去开启NFC                startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));                return 0;            }        }        return 1;    }

建议以上代码放入NfcBaseActivity的onCreate中,当你的程序需要调用NFC时直接继承即可。
2、NFC前台调度系统
NFC中有两种响应标签的方式,一种是前台调度系统,另一种是intent过滤器的方式。前台调度系统其实就是运行Activity高优先的来处理Tag的技术,前台调用系统的优先级要高于intent过滤器。但前台调度系统要求Activity是被打开的。
首先我们需要在Activity被创建时,去初始化NFC的信息

    private NfcAdapter nfcAdapter;    private NfcManager nfcManager;    private PendingIntent pendingIntent;    private IntentFilter[] intentFilters;    private String[][] mTechList;    private void nfcInitialization(){        //该参数的作用是指定用哪个Activity来处理标签        //参数1:上下文        // 参数二 不使用了——0,        // 参数三:一个意图用来存储信息,这里会根据这个意图来调用指定Activity        //FLAG_ACTIVITY_SINGLE_TOP:指定Activity不能被重复创建        // 参数四:对参数的操作标志        pendingIntent= PendingIntent.getActivity(            this,0,            newIntent(this,getClass())            .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)            ,0);            //创建意图过滤器,指定该前台调度系统拦截那些类型的标签            //这里说明IntentFilter不是很熟悉的童鞋先去查一下这里的资料            //在这里我们现在*/*表示拦截所有标签        IntentFilter intentFilter=new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);        IntentFilter intentFilter1=new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);        try {            intentFilter.addDataType("*/*");        } catch (IntentFilter.MalformedMimeTypeException e) {            e.printStackTrace();        }        //将我们的意图放入到数组中(在我的案例中,intentFilter1其实是没有使用的)        intentFilters=new IntentFilter[]{intentFilter,intentFilter1};        //指定过滤标签,这里填入null就好        mTechList=null;    }

这里我们初始化了前台调度系统的一些参数,下面我们看一下怎么启用前台调度系统

//在activity不可见的时候我们关闭前台调度 @Override    protected void onPause() {        super.onPause();        if(nfcAdapter!=null)            nfcAdapter.disableForegroundDispatch(this);    }    //在Activity显示的时候,我们让NFC前台调度系统处于打开状态    @Override    protected void onResume() {        super.onResume();        Log.w("nfclive","resume"+nfcAdapter);        if(nfcAdapter!=null)        nfcAdapter.enableForegroundDispatch(this,pendingIntent,    intentFilters,mTechList);    }

当完成这些代码后,我们就可以将标签拦截,不在向下传递。
当我们拦截到标签后,我们需要获取标签中的信息,由于我们在前面采用了FLAG_ACTIVITY_SINGLE_TOP,所以在每次刷入标签时不会去调用onCreate而是调用onNewIntent来经行回调,且会将Tag放入到Intent中。下面我们通过一些代码来尝试获取NFC标签中的Uid和Tag对象,并将uid转为字符串

    protected void onNewIntent(Intent intent) {        super.onNewIntent(intent);        //这里我们去得到tag对象        tag=intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);        uid= getUid(tag);        //Uid样子:4-106-91-119-72-2-78    }     public static String getUid(Tag tag){         //获取tag中ID的byte数组        byte[] tagByteId=tag.getId();        //通过流来经行解析为字符串        StringBuffer stringBuffer=new StringBuffer();        for (byte b:tagByteId){            stringBuffer.append(b);        }        return stringBuffer.toString();     }

当然,单纯的只获取ID对我们来说可能并不满足,我们想获取一下NFC中的存放了说明数据,接下来让我们去获取一下NFC中的数据。
在看数据之前让我们来看一下NFC中的数据结构吧
Parcelable[] rawmsgs=intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);来获取NdefMessage消息,在这里Parcelable和NdefMessage是实现关系。下面是我的一段代码的实现,我们只讲第一个NdefMessage取出。

public static NdefMessage getNdefMessage(Intent intent) {        NdefMessage[] ndefMessage=null;        Parcelable[] rawmsgs=intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);        if (rawmsgs!=null){            ndefMessage=new NdefMessage[rawmsgs.length];            for (int i=0;i<rawmsgs.length;i++){                ndefMessage[i]= (NdefMessage) rawmsgs[i];            }        }        return ndefMessage[0];    }

这样我们就可以得到NdefMessage了,但是我们通过这个消息如何解析到我们想要的数据呢?其实在NdefMessage中,又包含了多个NdefRecord,每个NdefRecord就表示一个NFC数据的记录,可以通过message.getRecords()来获取。
NdefRecord[] record=message.getRecords()
然后我们需要解析的是record中的消息如果你是NDEF消息,先把这个东西copy到你的代码中

public static final Map<Byte, String> URI_PREFIX_MAP = new HashMap<Byte, String>();    static {        //设置NDEF Uri规范支持的Uri前缀,在解析payload时,需要根据payload的第1个字节定位相应的uri前缀        URI_PREFIX_MAP.put((byte) 0x00, "");        URI_PREFIX_MAP.put((byte) 0x01, "http://www.");        URI_PREFIX_MAP.put((byte) 0x02, "https://www.");        URI_PREFIX_MAP.put((byte) 0x03, "http://");        URI_PREFIX_MAP.put((byte) 0x04, "https://");        URI_PREFIX_MAP.put((byte) 0x05, "tel:");        URI_PREFIX_MAP.put((byte) 0x06, "mailto:");        URI_PREFIX_MAP.put((byte) 0x07, "ftp://anonymous:anonymous@");        URI_PREFIX_MAP.put((byte) 0x08, "ftp://ftp.");        URI_PREFIX_MAP.put((byte) 0x09, "ftps://");        URI_PREFIX_MAP.put((byte) 0x0A, "sftp://");        URI_PREFIX_MAP.put((byte) 0x0B, "smb://");        URI_PREFIX_MAP.put((byte) 0x0C, "nfs://");        URI_PREFIX_MAP.put((byte) 0x0D, "ftp://");        URI_PREFIX_MAP.put((byte) 0x0E, "dav://");        URI_PREFIX_MAP.put((byte) 0x0F, "news:");        URI_PREFIX_MAP.put((byte) 0x10, "telnet://");        URI_PREFIX_MAP.put((byte) 0x11, "imap:");        URI_PREFIX_MAP.put((byte) 0x12, "rtsp://");        URI_PREFIX_MAP.put((byte) 0x13, "urn:");        URI_PREFIX_MAP.put((byte) 0x14, "pop:");        URI_PREFIX_MAP.put((byte) 0x15, "sip:");        URI_PREFIX_MAP.put((byte) 0x16, "sips:");        URI_PREFIX_MAP.put((byte) 0x17, "tftp:");        URI_PREFIX_MAP.put((byte) 0x18, "btspp://");        URI_PREFIX_MAP.put((byte) 0x19, "btl2cap://");        URI_PREFIX_MAP.put((byte) 0x1A, "btgoep://");        URI_PREFIX_MAP.put((byte) 0x1B, "tcpobex://");        URI_PREFIX_MAP.put((byte) 0x1C, "irdaobex://");        URI_PREFIX_MAP.put((byte) 0x1D, "file://");        URI_PREFIX_MAP.put((byte) 0x1E, "urn:epc:id:");        URI_PREFIX_MAP.put((byte) 0x1F, "urn:epc:tag:");        URI_PREFIX_MAP.put((byte) 0x20, "urn:epc:pat:");        URI_PREFIX_MAP.put((byte) 0x21, "urn:epc:raw:");        URI_PREFIX_MAP.put((byte) 0x22, "urn:epc:");        URI_PREFIX_MAP.put((byte) 0x23, "urn:nfc:");    }

这是一些头函数代表的含义
接下来我们获取一下NFC中字节流
byte[] bytes=records[0].getPayload();
然后我们来判断一下NDEF的类型records[0].getType();
在NdefRecord定义了

    public static final byte[] RTD_ALTERNATIVE_CARRIER ;    public static final byte[] RTD_HANDOVER_CARRIER ;    public static final byte[] RTD_HANDOVER_REQUEST l;    public static final byte[] RTD_HANDOVER_SELECT ;    public static final byte[] RTD_SMART_POSTER ;    public static final byte[] RTD_TEXT ;    public static final byte[] RTD_URI ;

这些格式。RTD_TEXT 是文本格式,RTD_URI是可以直接调用系统。这是比较常用的两个,其中URI又可以指定这些类型

    public static final short TNF_ABSOLUTE_URI = 3;//绝对URI    public static final short TNF_EMPTY = 0;    public static final short TNF_EXTERNAL_TYPE = 4;    public static final short TNF_MIME_MEDIA = 2;    public static final short TNF_UNCHANGED = 6;    public static final short TNF_UNKNOWN = 5;    public static final short TNF_WELL_KNOWN = 1;//已知类型,NDEF论坛定义

若我们解析的数据仅为TEXT类型时,只需要将字节的第一位取出,判断编码格式,其他位按照指定编码进行解析

public static  String parseWellKonwnUriRecord(NdefMessage message){        NdefRecord[] records=message.getRecords();        byte[]bytes=records[0].getPayload();        byte charData=bytes[0];        byte[] data=new byte[bytes.length-1];        System.arraycopy(bytes,1,data,0,data.length);        LogUtil.w("-------------------------"+new String(data,charData==1?"UTF-8","GBK"));        return new String(data,charData==1?"UTF-8","GBK");    }

RTD_URI 方式和读取字符串类似,只是没有首位的编码位;TNF_WELL_KNOWN 类型时,表示数据为已知类型,从URI_PREFIX_MAP中获取首位对应的字符串即可。


以上就是NFC的读卡模式,下面我们来说一下NFC的写入模式
其实NFC的写卡模式与NFC的读卡模式是相似的。
首先我们需要将信息准备好!如URI,或text信息
然后我们创建一个 NdefRecord record=new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload);
NdefRecord.TNF_WELL_KNOWN:表示已知数据类型
NdefRecord.RTD_TEXT:为指定数据的格式
payload:为准备好的字节数据
然后就可以生成一个NdefRecord,在将多个或一个NdefRecord放入NdefMessage中

new NdefMessage(record,arrRecord);

然后我们在onNewIntent,获取到Ndef对象Ndef ndef=Ndef.get(getTag());
经行提交:ndef.connect();,接下来判断是否NFC标签的标签是否可以写入

if (ndef.getMaxSize() < message.getByteArrayLength()){     Toast.makeText(this,"NFC标签空间不足",Toast.LENGTH_SHORT).show();     return;}else if (ndef==null){     Toast.makeText(this,"非NDEF数据",Toast.LENGTH_SHORT).show();     writeTag(ndefMessage, tag);//通过这种方式写入     Toast.makeText(this,"完成",Toast.LENGTH_SHORT).show();     return;}ndef.writeNdefMessage(message);

好了,以上就是NFC标签的读写方式,由于本人表达能力有限,有不清楚或是不理解的地方可以发表评论。

0 0