NFC技术解析,NFC开发简单入门

2020-03-14 08:10 来源:未知

六、非NDEF格式(操作步骤如上图,具体实现查阅项目代码)

Android NFC Demo1

4.读取NFC芯片中内容
@Override
    public void onNewIntent(Intent intent) {
        //1.获取Tag对象
        Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        //2.获取Ndef的实例
        Ndef ndef = Ndef.get(detectedTag);
        mTagText = ndef.getType()   "nmaxsize:"   ndef.getMaxSize()   "bytesnn";
        readNfcTag(intent);
        mNfcText.setText(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   "nntextn"   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();
        }
    }

     好了现在开始上代码以及解释。首先我们我们字啊Android studio开始一个工程,在AndroidManifest清单文件里面设置项目权限nfc,要求当前设备必须要有NFC芯片,没有就GG了

向NFC标签写入数据一般分为三步:

6.在manifest文件中需要设置的部分有:

3.当前Activity声明周期的判断
private NfcAdapter mNfcAdapter;
private PendingIntent mPendingIntent;

@Override
    protected void onStart() {
        super.onStart();
        mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
        //一旦截获NFC消息,就会通过PendingIntent调用窗口
        mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0);
    }
    /**
     * 获得焦点,按钮可以点击
     */
    @Override
    public void onResume() {
        super.onResume();
        //后面两个null,null设置处理优于所有其他NFC的处理
        if (mNfcAdapter != null)
            mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
    }
    /**
     * 暂停Activity,界面获取焦点,按钮可以点击
     */
    @Override
    public void onPause() {
        super.onPause();
        //恢复默认状态
        if (mNfcAdapter != null)
            mNfcAdapter.disableForegroundDispatch(this);
    }

2.Android SDK API支持下面3种NDEF数据的操作:

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

设置Activity的Intent Filter,比如设置为三种过滤机制的一种:

5.写入NFC芯片
 @Override
    public void onNewIntent(Intent intent) {
        if (mText == null)
            return;
        //获取Tag对象
        Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        NdefMessage ndefMessage = new NdefMessage(
                new NdefRecord[] { createTextRecord(mText) });
        boolean result = writeTag(ndefMessage, detectedTag);
        if (result){
            Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "写入失败", Toast.LENGTH_SHORT).show();
        }
    }
    /**
     * 创建NDEF文本数据
     * @param text
     * @return
     */
    public static NdefRecord createTextRecord(String text) {
        byte[] langBytes = Locale.CHINA.getLanguage().getBytes(Charset.forName("US-ASCII"));
        Charset utfEncoding = Charset.forName("UTF-8");
        //将文本转换为UTF-8格式
        byte[] textBytes = text.getBytes(utfEncoding);
        //设置状态字节编码最高位数为0
        int utfBit = 0;
        //定义状态字节
        char status = (char) (utfBit   langBytes.length);
        byte[] data = new byte[1   langBytes.length   textBytes.length];
        //设置第一个状态字节,先将状态码转换成字节
        data[0] = (byte) status;
        //设置语言编码,使用数组拷贝方法,从0开始拷贝到data中,拷贝到data的1到langBytes.length的位置
        System.arraycopy(langBytes, 0, data, 1, langBytes.length);
        //设置文本字节,使用数组拷贝方法,从0开始拷贝到data中,拷贝到data的1   langBytes.length
        //到textBytes.length的位置
        System.arraycopy(textBytes, 0, data, 1   langBytes.length, textBytes.length);
        //通过字节传入NdefRecord对象
        //NdefRecord.RTD_TEXT:传入类型 读写
        NdefRecord ndefRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,
                NdefRecord.RTD_TEXT, new byte[0], data);
        return ndefRecord;
    }
    /**
     * 写数据
     * @param ndefMessage 创建好的NDEF文本数据
     * @param tag 标签
     * @return
     */
    public static boolean writeTag(NdefMessage ndefMessage, Tag tag) {
        try {
            Ndef ndef = Ndef.get(tag);
            ndef.connect();
            ndef.writeNdefMessage(ndefMessage);
            return true;
        } catch (Exception e) {
        }
        return false;
    }

核心的代码已经贴出,查看详情的代码,请点击这里,已经简化成工具类,可直接拷贝使用。

美高梅网投网址 1

点击自动打开短信界面或百度页面,进入对应Activity,将NFC标签贴近手机背面,提示写入成功。返回主界面,再将NFC标签贴近手机背面,便能看到自动打开短信或者打开百度页面。

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

NFC相比于蓝牙的优势

蓝牙4.0相比于以前版本,功耗低,传输速度快,可以在10m之内使用。
NFC技术优势是创建连接快,传输速度也不慢,存储芯片中的数据可以加密安全性较高,在20cm之内使用。

//格式化并将信息写入标签

美高梅网投网址 2由飞利浦公司和索尼公司共同开发的NFC是一种非接触式识别和互联技术

  TECH_DISCOVERED:

  1. NFC是什么
  2. NFC的原理
  3. NFC工作模式和实用场景
  4. NFC相比于蓝牙的优势
  5. Android读取和写入NDEF格式的NFC芯片
  6. Android读取和写入非NDEF格式的NFC芯片

    写书标签数据的代码如下,获取标签中获取到的标签tag对象,new一个NdefMessage把我们提前定义的字符串穿进去,看一下源码,我们传进去的是系统短信的包名com.android.mms

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

android:minSdkVersion="14"

Android读取和写入NDEF格式的NFC芯片

首先说明NFC芯片可以根据厂家定制,一次性写入然后只能读,简单的可读可写。目前Android SDK API主要支持NFC论坛标准(Forum Standard),这种标准被称为NDEF。

if(ndef !=null) {

美高梅网投网址 3数据写入界面美高梅网投网址 4数据读取界面

1.读卡器模式:

1.支持NFC功能,添加权限
<uses-permission android:name="android.permission.NFC" />
<!-- 要求当前设备必须要有NFC芯片 -->
<uses-feature android:name="android.hardware.nfc" android:required="true" />

if(format !=null) {

2)判断NFC标签的数据类型(通过Ndef.get方法)

2.仿真卡模式:

NFC工作模式和实用场景

NFC工作模式分为三种:

  • 读卡器模式,指含有NFC芯片的标签,可以被支持NFC的手机或者专门读卡器设备读取或者写入数据。一般可以用于巡更,用支持NFC的手机到定点区读取NFC芯片的数据然后传输到后台表示已巡视了定点区。
  • 仿真卡模式,指含有IC卡的NFC芯片,可以使用支持NFC的手机或者NFC射频器读取出NFC芯片中IC卡的信息。常见的由交通卡,信用卡。
  • 点对点模式,指两台NFC设备之间互相都可以进行数据 交换。

return;

NFC是Near Field Communication缩写,即近距离无线通讯技术。可以在移动设备、消费类电子产品、PC 和智能控件工具间进行近距离无线通信。简单一点说,nfc功能是什么?nfc功能有什么用?其实NFC提供了一种简单、触控式的解决方案,可以让消费者简单直观地交换信息、访问内容与服务。NFC技术允许电子设备之间进行非接触式点对点数据传输,在十厘米内,交换数据,其传输速度有106Kbit/秒、212Kbit/秒或者424Kbit/秒三种。接下来我们更加详细的来了解一下nfc的应用。

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


if(!ndef.isWritable()) {

3)写入数据

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

2.当前Activity的清单文件中的设置
<activity
    android:name="com.example.NFCActivity"
    android:launchMode="singleTask" >
    <intent-filter>    
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

if(ndef.getMaxSize() < size) {

MifareUltralight数据格式:将NFC标签的存储区域分为16个页,每一个页可以存储4个字节,一个可存储64个字节。页码从0开始。前4页存储了NFC标签相关的信息(如NFC标签的序列号、控制位等)。从第5页开始存储实际的数据。使用MifareUltralight.get方法获取MifareUltralight对象,然后调用MifareUltralight.connect方法进行连接,并使用MifareUltralight.writePage方法每次写入1页。

2.仿真卡模式;

NFC是什么

NFC是Near Field Communication的简称,意思为近距离无线通讯技术,简单的说是能够在短距离之内与兼容设备实现数据交换的技术。

Toast.makeText(this,"写入数据失败",Toast.LENGTH_SHORT).show();

美高梅网投网址 5

b.向NFC标签写入NDEF格式的数据;

NFC的原理

NFC是使用非接触式射频技术实现的数据交换技术,在13.56MHz频率20厘米距离内进行传输,其传输速度有106 Kbit/秒、212 Kbit/秒或者424 Kbit/秒三种。

前言:

美高梅网投网址 6

3.点对点模式:

本篇博客是为了解决以下的问题:

.createApplicationRecord(mNfctagName)});

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

只过滤固定格式的NDEF数据。例如:纯文本、指定协议(http、ftp、smb等)的URI等;

Android读取和写入非NDEF格式的NFC芯片

对于非NDEF格式数据的NFC芯片,其中的数据格式是自定义的,但是存储到芯片中都是以字节码的形式。想深入学习的朋友可以,参考Github源码,编译生成的APK能够读取部分地区交通卡信息。


感谢以下知识的分享:
Android 高级开发——NFC标签开发深度解析
NFC百度百科

nfc的基础Activity

该模式与蓝牙、红外差不多,用于不同NFC设备之间进行数据交换,不过这个模式已经没有有“刷”的感觉了。其有效距离一般不能超过4厘米,但传输建立速度要比红外和蓝牙技术快很多,传输速度比红外块得多,如过双方都使用Android4.2,NFC会直接利用蓝牙传输。这种技术被称为AndroidBeam。所以使用androidBeam传输数据的两部设备不再限于4厘米之内。

Near Field Communication 近场通信,是一种数据传输技术。

(5)NfcManager:NFC adapter的管理器,列出所有本地Android设备支持所有的NFC adapter.

实际运行效果如下:

接下来,我们来第一个例子,这个例子是属于读卡器模式,从NFC芯片中读取和写入数据。

       截图就不上传了,因为只是写了一下入门的小demo,分享下自己所得,感谢大家的阅读,语言组织不合适的地方还请包涵,谢谢。

2)可变的长度类型必须是NdefRecord.RTD_TEXT。

1.Android SDK API主要支持NFC论坛标准(Forum Standard),这种标准被称为NDEF(NFC Data Exchange Format,NFC数据交换格式);

Toast.makeText(this,"写入数据成功",Toast.LENGTH_SHORT).show();

美高梅网投网址 7配置权限

与wifi、蓝牙、红外线等数据传输技术的一个主要差异就是有效距离一般不能超过4cm。

}

美高梅网投网址 8应用主界面美高梅网投网址 9数据写入界面美高梅网投网址 10扫描NFC标签后跳转页面

基础知识:

//3.写入数据

1)TNF(类型名格式,Type Name Format)必须是NdefRecord.TNF_WELL_KNOWN。

a.从NFC标签读取NDEF格式的数据;

美高梅网投网址 11

NFC工作模式主要有三种工作模式,分别是卡模式(Card emulation)、点对点模式和读卡器模式(Reader/writer mode)。

此过程的处理流程如下图所示:

}

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

限制安装的设备:

}catch(Exception e) {

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

设置权限:

//判断是否支持可写

五、NDEF Uri格式存储(操作步骤如上图,具体实现可查阅项目代码)

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;

import android.media.AudioManager;
import android.media.MediaPlayer;
import android.media.RingtoneManager;
import android.net.Uri;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.MifareUltralight;
import android.nfc.tech.Ndef;
import android.nfc.tech.NfcA;
import android.os.Bundle;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class NfcDemoActivity extends Activity implements OnClickListener {

    // NFC适配器
    private NfcAdapter nfcAdapter = null;
    // 传达意图
    private PendingIntent pi = null;
    // 滤掉组件无法响应和处理的Intent
    private IntentFilter tagDetected = null;
    // 文本控件
    private TextView promt = null;
    // 是否支持NFC功能的标签
    private boolean isNFC_support = false;
    // 读、写、删按钮控件
    private Button readBtn, writeBtn, deleteBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_nfc_demo);
        setupViews();
        initNFCData();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (isNFC_support == false) {
            // 如果设备不支持NFC或者NFC功能没开启,就return掉
            return;
        }
        // 开始监听NFC设备是否连接
        startNFC_Listener();

        if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(this.getIntent()
                .getAction())) {
            // 注意这个if中的代码几乎不会进来,因为刚刚在上一行代码开启了监听NFC连接,下一行代码马上就收到了NFC连接的intent,这种几率很小
            // 处理该intent
            processIntent(this.getIntent());
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (isNFC_support == true) {
            // 当前Activity如果不在手机的最前端,就停止NFC设备连接的监听
            stopNFC_Listener();
        }
    }

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

    @Override
    public void onClick(View v) {

        // 点击读按钮后
        if (v.getId() == R.id.read_btn) {
            try {
                String content = read(tagFromIntent);
                if (content != null && !content.equals("")) {
                    promt.setText(promt.getText()   "nfc标签内容:n"   content
                              "n");
                } else {
                    promt.setText(promt.getText()   "nfc标签内容:n"   "内容为空n");
                }
            } catch (IOException e) {
                promt.setText(promt.getText()   "错误:"   e.getMessage()   "n");
                Log.e("myonclick", "读取nfc异常", e);
            } catch (FormatException e) {
                promt.setText(promt.getText()   "错误:"   e.getMessage()   "n");
                Log.e("myonclick", "读取nfc异常", e);
            }
            // 点击写后写入
        } else if (v.getId() == R.id.write_btn) {
            try {
                write(tagFromIntent);
            } catch (IOException e) {
                promt.setText(promt.getText()   "错误:"   e.getMessage()   "n");
                Log.e("myonclick", "写nfc异常", e);
            } catch (FormatException e) {
                promt.setText(promt.getText()   "错误:"   e.getMessage()   "n");
                Log.e("myonclick", "写nfc异常", e);
            }
        } else if (v.getId() == R.id.delete_btn) {
            try {
                delete(tagFromIntent);
            } catch (IOException e) {
                promt.setText(promt.getText()   "错误:"   e.getMessage()   "n");
                Log.e("myonclick", "删除nfc异常", e);
            } catch (FormatException e) {
                promt.setText(promt.getText()   "错误:"   e.getMessage()   "n");
                Log.e("myonclick", "删除nfc异常", e);
            }
        }
    }

    private void setupViews() {
        // 控件的绑定
        promt = (TextView) findViewById(R.id.promt);
        readBtn = (Button) findViewById(R.id.read_btn);
        writeBtn = (Button) findViewById(R.id.write_btn);
        deleteBtn = (Button) findViewById(R.id.delete_btn);
        // 给文本控件赋值初始文本
        promt.setText("等待RFID标签");
        // 监听读、写、删按钮控件
        readBtn.setOnClickListener(this);
        writeBtn.setOnClickListener(this);
        deleteBtn.setOnClickListener(this);
    }

    private void initNFCData() {
        // 初始化设备支持NFC功能
        isNFC_support = true;
        // 得到默认nfc适配器
        nfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
        // 提示信息定义
        String metaInfo = "";
        // 判定设备是否支持NFC或启动NFC
        if (nfcAdapter == null) {
            metaInfo = "设备不支持NFC!";
            Toast.makeText(this, metaInfo, Toast.LENGTH_SHORT).show();
            isNFC_support = false;
        }
        if (!nfcAdapter.isEnabled()) {
            metaInfo = "请在系统设置中先启用NFC功能!";
            Toast.makeText(this, metaInfo, Toast.LENGTH_SHORT).show();
            isNFC_support = false;
        }

        if (isNFC_support == true) {
            init_NFC();
        } else {
            promt.setTextColor(Color.RED);
            promt.setText(metaInfo);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.nfc_demo, menu);
        return true;
    }

    // 字符序列转换为16进制字符串
    private String bytesToHexString(byte[] src) {
        return bytesToHexString(src, true);
    }

    private String bytesToHexString(byte[] src, boolean isPrefix) {
        StringBuilder stringBuilder = new StringBuilder();
        if (isPrefix == true) {
            stringBuilder.append("0x");
        }
        if (src == null || src.length <= 0) {
            return null;
        }
        char[] buffer = new char[2];
        for (int i = 0; i < src.length; i  ) {
            buffer[0] = Character.toUpperCase(Character.forDigit(
                    (src[i] >>> 4) & 0x0F, 16));
            buffer[1] = Character.toUpperCase(Character.forDigit(src[i] & 0x0F,
                    16));
            System.out.println(buffer);
            stringBuilder.append(buffer);
        }
        return stringBuilder.toString();
    }

    private Tag tagFromIntent;

    /**
     * Parses the NDEF Message from the intent and prints to the TextView
     */
    public void processIntent(Intent intent) {
        if (isNFC_support == false)
            return;

        // 取出封装在intent中的TAG
        tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);

        promt.setTextColor(Color.BLUE);
        String metaInfo = "";
        metaInfo  = "卡片ID:"   bytesToHexString(tagFromIntent.getId())   "n";
        Toast.makeText(this, "找到卡片", Toast.LENGTH_SHORT).show();

        // Tech List
        String prefix = "android.nfc.tech.";
        String[] techList = tagFromIntent.getTechList();

        //分析NFC卡的类型: Mifare Classic/UltraLight Info
        String CardType = "";
        for (int i = 0; i < techList.length; i  ) {
            if (techList[i].equals(NfcA.class.getName())) {
                // 读取TAG
                NfcA mfc = NfcA.get(tagFromIntent);
                try {
                    if ("".equals(CardType))
                        CardType = "MifareClassic卡片类型 n 不支持NDEF消息 n";
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else if (techList[i].equals(MifareUltralight.class.getName())) {
                MifareUltralight mifareUlTag = MifareUltralight
                        .get(tagFromIntent);
                String lightType = "";
                // Type Info
                switch (mifareUlTag.getType()) {
                case MifareUltralight.TYPE_ULTRALIGHT:
                    lightType = "Ultralight";
                    break;
                case MifareUltralight.TYPE_ULTRALIGHT_C:
                    lightType = "Ultralight C";
                    break;
                }
                CardType = lightType   "卡片类型n";

                Ndef ndef = Ndef.get(tagFromIntent);
                CardType  = "最大数据尺寸:"   ndef.getMaxSize()   "n";

            }
        }
        metaInfo  = CardType;
        promt.setText(metaInfo);
    }

    // 读取方法
    private String read(Tag tag) throws IOException, FormatException {
        if (tag != null) {
            //解析Tag获取到NDEF实例
            Ndef ndef = Ndef.get(tag);
            //打开连接
            ndef.connect();
            //获取NDEF消息
            NdefMessage message = ndef.getNdefMessage();
            //将消息转换成字节数组
            byte[] data = message.toByteArray();
            //将字节数组转换成字符串
            String str = new String(data, Charset.forName("UTF-8"));
            //关闭连接
            ndef.close();
            return str;
        } else {
            Toast.makeText(NfcDemoActivity.this, "设备与nfc卡连接断开,请重新连接...",
                    Toast.LENGTH_SHORT).show();
        }
        return null;
    }

    // 写入方法
    private void write(Tag tag) throws IOException, FormatException {
        if (tag != null) {
            //新建NdefRecord数组,本例中数组只有一个元素
            NdefRecord[] records = { createRecord() };
            //新建一个NdefMessage实例
            NdefMessage message = new NdefMessage(records);
            // 解析TAG获取到NDEF实例
            Ndef ndef = Ndef.get(tag);
            // 打开连接
            ndef.connect();
            // 写入NDEF信息
            ndef.writeNdefMessage(message);
            // 关闭连接
            ndef.close();
            promt.setText(promt.getText()   "写入数据成功!"   "n");
        } else {
            Toast.makeText(NfcDemoActivity.this, "设备与nfc卡连接断开,请重新连接...",
                    Toast.LENGTH_SHORT).show();
        }
    }

    // 删除方法
    private void delete(Tag tag) throws IOException, FormatException {
        if (tag != null) {
            //新建一个里面无任何信息的NdefRecord实例
            NdefRecord nullNdefRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA,
                    new byte[] {}, new byte[] {}, new byte[] {});
            NdefRecord[] records = { nullNdefRecord };
            NdefMessage message = new NdefMessage(records);
            // 解析TAG获取到NDEF实例
            Ndef ndef = Ndef.get(tag);
            // 打开连接
            ndef.connect();
            // 写入信息
            ndef.writeNdefMessage(message);
            // 关闭连接
            ndef.close();
            promt.setText(promt.getText()   "删除数据成功!"   "n");
        } else {
            Toast.makeText(NfcDemoActivity.this, "设备与nfc卡连接断开,请重新连接...",
                    Toast.LENGTH_SHORT).show();
        }
    }

    //返回一个NdefRecord实例
    private NdefRecord createRecord() throws UnsupportedEncodingException {
        //组装字符串,准备好你要写入的信息
        String msg = "BEGIN:VCARDn"   "VERSION:2.1n"   "中国湖北省武汉市n"
                  "武汉大学计算机学院n"   "END:VCARD";
        //将字符串转换成字节数组
        byte[] textBytes = msg.getBytes();
        //将字节数组封装到一个NdefRecord实例中去
        NdefRecord textRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA,
                "text/x-vCard".getBytes(), new byte[] {}, textBytes);
        return textRecord;
    }

    private MediaPlayer ring() throws Exception, IOException {
        // TODO Auto-generated method stub
        Uri alert = RingtoneManager
                .getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        MediaPlayer player = new MediaPlayer();
        player.setDataSource(this, alert);
        final AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
        if (audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION) != 0) {
            player.setAudioStreamType(AudioManager.STREAM_NOTIFICATION);
            player.setLooping(false);
            player.prepare();
            player.start();
        }
        return player;
    }

    private void startNFC_Listener() {
        // 开始监听NFC设备是否连接,如果连接就发pi意图
        nfcAdapter.enableForegroundDispatch(this, pi,
                new IntentFilter[] { tagDetected }, null);
    }

    private void stopNFC_Listener() {
        // 停止监听NFC设备是否连接
        nfcAdapter.disableForegroundDispatch(this);
    }

    private void init_NFC() {
        // 初始化PendingIntent,当有NFC设备连接上的时候,就交给当前Activity处理
        pi = PendingIntent.getActivity(this, 0, new Intent(this, getClass())
                .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
        // 新建IntentFilter,使用的是第二种的过滤机制
        tagDetected = new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED);
        tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
    }

}

NdefFormatable format = NdefFormatable.get(tag);

2)定义可接收Tag的Activity,配置一下launchMode属性:

它的Activity的内容如下,包括读取、写入、删除三大功能:(其中删除功能是通过写入空值来实现的)

//转换成字节获得大小

1)获取Tag对象

美高梅网投网址 12

对了在这里说下Android api版本的区别

点击写NFC标签中的文本数据,跳转到对应的Activity,将NFC标签卡贴近手机,写入成功后会提示,再退回主页面,选择读文本数据,便可读取。

2.Android SDK API支持如下三种NDEF数据的操作:

if(tag ==null) {

美高梅网投网址 13写文本数据核心代码,具体可查阅项目中代码WriteTextActivity类美高梅网投网址 14读文本数据核心代码,具体可查阅项目中代码ReadTextActivity类

如果将NFC过滤机制看成if...else if...else语句的话,那么这种过滤机制就相当于else部分,当前面两种过滤机制都匹配失败后,系统就会利用这种过滤机制来处理,这种过滤机制用来处理未识别的Tag(数据格式不对,而且Tag支持的格式也不匹配)。

      然后获取NdefMessage对象字节长度,通过Ndef.get(Ndef 对tag查询属性和进行I/O操作的类。Ndef是NFC-F (JIS 6319-4)技术标准 )。判断ndef是否为NDEF格式的标签,是的话调用连接,判断是否支持可写,再判断标签的容量和现在的写入的数据长度比较,都符合的情况下开始writeNdefMessage写入数据。不是NDEF格式的话,还有就是我们刚买来的的NFC的标签贴纸是没有分区或者格式化,这个时候我们就需要格式化一下NdefFormatable.get(tag),判断是否获得了NdefFormatable格式化对象,有一些标签是只读的或者不允许格式化的。然后再格式化写入数据。好了,到此为止我们就已经完成了nfc数据的写入,读取的时候就是在onNewIntent里面获取tag标签数据。在设备里面有这个标签对象的时候,nfc标签再贴近设备的时候就会执行我们想要的操作,跳转到系统的短信界面,下面是数据写入的代码。

3)通过Android Beam技术将NDEF数据发送到另一部NFC设备。

下面是该示例的完整源码下载链接:

(3)Tag:表示一个被动的NFC的目标,tag对象将被创建并且封装到一个Intent里,然后NFC 发布系统将这个Intent用startActivity发送到注册了接受这种Intent的activity里。简单来说就是比如现在使用的公交卡,电梯卡,就是这个Tag,里面封装了一个tag对象,当注册了

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

1.读卡器模式;

public voidwriteNFCTag(Tag tag) {

不管什么格式的数据本质上都是由一些字节组成的。对于NDEF文本格式来说,这些数据的第1个字节描述了数据的状态,然后若干个字节描述文本的语言编码,最后剩余字节表示文本数据。这些数据格式由NFC Forum的相关规范定义,可以通过 下载相关的规范。

c.通过Android Beam技术将NDEF数据发送到另一部NFC设备;

//判断是否为NDEF标签

也可以使用MifareUltralight.readPages方法每次连续读取4页。如果读取的页的序号超过15,则从头开始读。例如,从第15页开始读。readPages方法会读取14、15、0、1页的数据。

3.点对点模式;

(3)通过Android Beam技术将NDEF数据发送到另一部NFC设备。

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

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

}

美高梅网投网址 15此为本次测试所使用设备,手机:小米5 NFC标签卡:淘宝可购买

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

ndef.writeNdefMessage(ndefMessage);

近期由于项目需求,对Android NFC 技术进行了一定的了解和深入,整合了一些网络、书籍资料,此文章仅作为自己的学习笔记。

  TAG_DISCOVERED:

NdefMessage ndefMessage =newNdefMessage(newNdefRecord[]{NdefRecord

下面这两张表是规范中 3.2节 相对重要的翻译部分:

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

}

点对点模式

它的manifest文件内容如下:

intsize = ndefMessage.toByteArray().length;

数据在NFC芯片中,可以简单理解成“刷标签”。本质上就是通过支持NFC的手机或其它电子设备从带有NFC芯片的标签、贴纸、名片等媒介中读写信息。通常NFC标签是不需要外部供电的。当支持NFC的外设向NFC读写数据时,它会发送某种磁场,而这个磁场会自动的向NFC标签供电。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.r8c.nfc_demo"
    android:versionCode="110"
    android:versionName="1.1.0" >

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="17" />
    <!-- NFC权限声明 -->
    <uses-permission android:name="android.permission.NFC" />

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

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.r8c.nfc_demo.NfcDemoActivity"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:label="@string/app_name" 
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <!-- TECH_DISCOVERED类型的nfc -->
            <intent-filter>
                <action android:name="android.nfc.action.TECH_DISCOVERED" />
            </intent-filter>
            <!-- 后设资源  调用自己建立的文件夹xml中的文件 -->
            <meta-data
                android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter" />
        </activity>
    </application>

</manifest>

美高梅网投网址 16

1)从NFC标签读取NDEF格式的数据。

4.NDEF_DISCOVERED:

format.format(ndefMessage);

1)NdefMessage:描述NDEF格式的信息,实际上我们写入NFC标签的就是NdefMessage对象。

NFC简介:

//判断是否获得了NdefFormatable对象,有一些标签是只读的或者不允许格式化的

如果这两个标准同时满足,那么就为NDEF格式。

5.Android系统会依次匹配NDEF_DISCOVERED、TECH_DISCOVERED和TAG_DISCOVERED;如果通过三重过滤机制仍然无法匹配Tag,则什么都不做;通常在成功匹配Tag后,Android设备会发出比较清脆的声音,而未成功匹配Tag,就会发出比较沉闷的声音。

return;

美高梅网投网址 17NFC、蓝牙和红外之间的差异

3.在一个NFC设备读取NFC标签或另一个NFC设备中的数据之前会在0.1秒的时间之内建立NFC连接,然后数据会自动从被读取一端流向读取数据的一端;数据接收端会根据具体的数据格式和标签类型调用相应的Activity(这种行为也称为Tag Dispatch),这些Activity都需要定义Intent Filter,这些Intent Filter中就会指定不同的过滤机制,分为三个级别,也称为NFC的三重过滤机制。

美高梅网投网址 18

场景是这样的:现将应用程序的包写到NFC程序上,然后我们将NFC标签靠近Android手机,手机就会自动运行包所对应的程序,这个是NFC比较基本的一个应用。下面以贴近标签自动运行Android自带的“短信”为例。

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

}

项目源码地址:

限制Android版本:

return;

读卡器模式

NFC支持3种工作模式:

美高梅网投网址,(4)NfcAdapter : 表示本地设备的NFC adapter,可以定义Intent来请求将系统检测到tags的提醒发送到你的Activity.并提供方法去注册前台tag提醒发布和前台NDEF推送。

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

(1)NdefMessage:描述NDEF格式的信息,实际上我们写入NFC标签的就是NdefMessage对象,所以我们可以理解为数据对象这样就简单多了。

2)NdefRecord:描述NDEF信息的一个信息段,一个NdefMessage可能包含一个或者多个NdefRecord。

(2)向NFC标签写入NDEF格式的数据。

美高梅网投网址 19处理NFC的Activity都要设置launchMode属性为singleTop或者singleTask,保证activty唯一实例

AndroidManifest

实现NFC标签中的文本数据的读写操作:

但是大部分Android 设备只有一个NFC adapter。

获取NFC标签中的数据要通过 NdefRecord.getPayload 方法完成。当然,在处理这些数据之前,最好判断一下NdefRecord对象中存储的是不是NDEF文本格式数据。

}else{

美高梅网投网址 20NDEF文本数据格式美高梅网投网址 21状态字节编码格式

2.在API level 10实现对tag的广泛的读写支持。

操作步骤:

1.Android中处理NFC重要的两个包 android.nfc 和 android.nfc.tech。

仿真卡模式

(2)NdefRecord:描述NDEF信息的一个信息段,一个NdefMessage可能包含一个或者多个NdefRecord,也就是对象中的一个个属性。

2)向NFC标签写入NDEF格式的数据。

打开系统短信界面BlNfcOpenMessageActivity

1.API level 9以前不支持NFC,当然现在市面上的系统基本上都是4.0以上,低版本的就暂时不考虑了。

ndef.connect();

android.nfc下面用到的类也是我们需要使用的:

      现在我们已经有了基础的NfcBLBaseActivity,现在我们做一个简单的入门,我们把nfc标签贴近Android设备写入一个数据到nfc标签,写入成功后把nfc标签移开Android设备,然后再把demo退出到后台,再把nfc标签贴近Android设备,这个时候Android设备跳转到系统的短信界面去。就是这样的一个操作场景。现在写一个界面继承NfcBLBaseActivity在onNewIntent中,界面打开的时候会去结束nfc标签的数据 获取tag对象,往设备里面写入我们的标签信息以便第二次打开的时候获取tag。

//判断标签的容量是否够用

     定义一个基础的接收nfc tag的activity,类似我们在项目中的基础baseActivity,通常来说为了让我们的设备在靠近nfc标签的时候,能够让我们的界面Activity调用起来,所以清单需要配置一下activity的 launchMode属性为singletop,子类需要在onCreate方法中做Activity初始化,子类需要在onNewIntent方法中进行NFC标签相关操作。当launchMode设置为singleTop时,第一次运行调用onCreate方法,第二次运行将不会创建新的Activity实例,将调用onNewIntent方法所以我们获取intent传递过来的tag数据操作放在onNewIntent方法中执行,如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent())。下面是baseActivity,在界面onStart的时候获取支持的nfcadapter,同时截获NFC消息,通过PendingIntent调用窗口。界面onResume和onPause的时候让设备处理当前NFC数据优先于其他的NFC处理。

Ndef ndef = Ndef.get(tag);

//判断NFC标签的数据类型(通过Ndef.get方法)

format.connect();

        说道NFC,是Near Field Communication缩写,就是近距离无线通讯技术。NFC采用主动和被动两种通信模式,工作的模式有三种,读写标签,点对点,仿真卡模式,今天我们只是简单的介绍一下读写标签(因为我已经废了一张公交卡了。。。。 大家在学习的时候可以去某宝买几张NFC标签贴纸。。),好了下面开始开始介绍。

}

try{

(1)从NFC标签读取NDEF格式的数据。

Toast.makeText(this,"写入数据成功",Toast.LENGTH_SHORT).show();

}

//Ndef格式类

//连接

}else{//当我们买回来的NFC标签是没有格式化的,或者没有分区的执行此步

TAG标签:
版权声明:本文由美高梅网投平台发布于美高梅网投网址,转载请注明出处:NFC技术解析,NFC开发简单入门