安卓之Nfc的使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/WQFAE01/article/details/79060819

NFC是Near Field Communication的缩写,也就是近场通信,是一种短距离数据传输技术,该功能相对于传统的蓝牙以及红外等数据传输功能各有利弊,是目前主流的近距离通信技术之一。NFC 提供了一种简单、触控式的解决方案,可以让手机用户简单直观地交换信息、访问内容与服务。
1、配置nfc的使用权限:

<uses-permission android:name="android.permission.NFC"/>    
<uses-feature android:name="android.hardware.nfc" android:required="true" />
//设置MainActivity的启动方式
android:launchMode="SingleTop" 

2、Nfc有三层的过滤机制:

1、ACTION_NDEF_DISCOVERED
2、ACTION_TECH_DISCOVERED
3、ACTION_TAG_DISCOVERED

Android按顺序匹配三层过滤机制的流程如下:
这里写图片描述

声明过滤机制:

<intent-filter>
    <action android:name="android.nfc.action.TECH_DISCOVERED" />
    <category android:name="android.intent.category.DEFAULT" />  
    <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data  
    android:name="android.nfc.action.TECH_DISCOVERED"                 
    android:resource="@xml/nfc_tech" />  
</activity>

使用TECH_DISCOVERED的过滤规则需先在/res/xml下面创建一个过滤规则文件,这个里面定义的是nfc实现的各种标准,每一个nfc卡都会符合多个不同的标准。
以下是在nfc_tech.xml定义的多种检测标准:

<tech-list>  
        <tech>android.nfc.tech.MifareClassic</tech>  
</tech-list>  
<tech-list>  
        <tech>android.nfc.tech.MifareUltralight</tech>  
</tech-list>  
<tech-list>  
        <tech>android.nfc.tech.IsoDep</tech>  
</tech-list>  
<tech-list>  
        <tech>android.nfc.tech.NfcA</tech>  
</tech-list>     
<tech-list>  
        <tech>android.nfc.tech.Ndef</tech>
        <tech>android.nfc.tech.NfcB</tech>  
</tech-list>  
//可以在一个<tech-list></tech-list>组中定义多个标准,如最后一组     

以上是使用nfc前的一些配置信息。
3、获取NfcAdapeter适配器

//获取Nfc适配器,判断设备是否支持nfc
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if(mNfcAdapter==null){
    Toast.makeText(this, "该设备比支持nfc", Toast.LENGTH_SHORT).show();
    return;
}
if(!mNfcAdapter.isEnabled()){
    Toast.makeText(this, "先打开nfc功能", Toast.LENGTH_SHORT).show();
    return;
}

4、因为设置的启动方式是”SingleTop”,在手机检测到有nfc标签时,系统会给当前的activity发送一个intent,就会调用onNewIntent(Intent intent)的方法,所以重写该方法,在该方法中对nfc标签进行解析。

protected void onNewIntent(Intent intent) {
    // TODO 自动生成的方法存根
    super.onNewIntent(intent);           
    //判断发来的intent是否我们设置的过滤机制,不是则退出不做处理  
    if (!NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction())) {  
         return;
    }   
    //获取到Tag标签对象    
    tag=intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
    if(tag!=null){
        //Tag标签中的Ndef内容
        ndef = Ndef.get(tag);
    }else{
        return;
    }   
    //获取此标签中支持的技术
    String[] techList=tag.getTechList();
    for (String tech:techList){           
        Log.d("TECH",tech);
    }
}

同时需要在onResume()和onPause()设置对nfc标签的连接的监听

PendingIntent pend = PendingIntent.getActivity(this, 0, new Intent(this, getClass())  
                .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);  
//开始监听nfc功能
protected void onResume() {
    // TODO 自动生成的方法存根
    super.onResume();
    if (mNfcAdapter != null) {
        //开始监听NFC设备是否连接,如果连接就发pend意图,设置当前程序为优先处理nfc的程序              
          mNfcAdapter.enableForegroundDispatch(this, pend, null, null);       
    }
}
//停止监听nfc
protected void onPause() {
    // TODO 自动生成的方法存根
    super.onPause();
    if (mNfcAdapter != null) {
        mNfcAdapter.disableForegroundDispatch(this);
    }
}

5、解析卡片的信息

//获取卡片的ID
tag.getId();    
//可将以下方法将ID转换成16进制码
private String bytesToHexString(byte[] bArray) {
   StringBuffer strBuf = new StringBuffer(bArray.length);
   String strTemp;
   for(int i = 0; i < bArray.length; i++) {
       strTemp = Integer.toHexString(0xFF & bArray[i]);
       if(strTemp.length() < 2) {
           strBuf.append(0);
       }
       strBuf.append(strTemp.toUpperCase());
   }
   return strBuf.toString();
}
//获取卡片类型
 String[] techList = tag.getTechList();         
//NFC卡的类型: Mifare Classic/UltraLight Info/IsoDep                 
 for (int i = 0; i < techList.length; i++) {
     //根据不同的卡片类型获取各自的Tag  
     if (techList[i].equals(NfcA.class.getName())) {  
         NfcA nfc = NfcA.get(tag);                  
         try {  
             if ("".equals(type))  
                Log.d("Type",NfcA.class.getName());                     
         } catch (Exception e) {  
             e.printStackTrace();  
         }  
     } else if (techList[i].equals(MifareUltralight.class.getName())) {  
         MifareUltralight mifareUlTag = MifareUltralight  
                 .get(tag);         
         switch (mifareUlTag.getType()) {  
         case MifareUltralight.TYPE_ULTRALIGHT:  
              Log.d("Type","ULTRALIGHT");
             break;  
         case MifareUltralight.TYPE_ULTRALIGHT_C:  
            Log.d("Type","ULTRALIGHT_C");
             break;  
         }                 
     }else if(techList[i].equals(IsoDep.class.getName())){
        Log.d("Type",IsoDep.class.getName());
     }
 }

6、读取卡片的内容:卡片的内容主要是这三种类型:1、文本类型,2、应用程序类型,3、Uri链接类型
应用程序跟Uri链接类型在andriod检测到nfc标签时可以快速启动程序或打开网页。

private void readIntent(){
      if (tag == null) {
           return;
       }              
      if(ndef==null){
           return;
      }                         
      try {
        //打开连接
        ndef.connect();     
        //读取标签中的ndef内容  
         NdefMessage message = ndef.getNdefMessage();
         //获取标签中的内容长度
         int length = message.getByteArrayLength();
         if(message==null){
             Toast.makeText(this, "Null Message", Toast.LENGTH_SHORT).show();
             ndef.close();
             return;
         }
         //一个NdefMessage是有一条或多条的NdefRecord组成。                       
         NdefRecord[] recoder = message.getRecords();
         for(NdefRecord r:recoder){
             //使用该方法获取该NdefRecord中的实际内容         
             byte[] b = r.getPayload(); 
             //如果直接使用r.toString()获取到的内容还包括了ndef格式中的一些前缀数据                       
         }
            //将消息转换成字节数组  
        //关闭连接  
        ndef.close();
    } catch (IOException e) {       
        // TODO 自动生成的 catch 块
        e.printStackTrace();
    }  
     catch (FormatException e) {
        // TODO 自动生成的 catch 块
        e.printStackTrace();
    }      
}

7、往标签中写入数据,上一节说到nfc的内容有主要是三种类型,不同的数据类型对应着不同的写入方式

//文本类型
NdefRecord recordText=new NdefRecord(NdefRecord.TNF_WELL_KNOWN,NdefRecord.RTD_TEXT,
                    new byte[]{0},"Hello World!".getBytes(Charset.forName("utf-8")));

//应用程序类型
NdefRecord recordPack=NdefRecord.createApplicationRecord(packageName);
//packageName是程序包名,可通过下面的方法获取系统中所有程序的包名
PackageManager manager = getPackageManager();
List<PackageInfo> packageInfos = manager.getInstalledPackages(PackageManager.GET_ACTIVITIES);
String[] mPackage = new String[packageInfos.size()];;
 //遍历
 int i=0;
 for (PackageInfo pi : packageInfos) {
     //获取软件名和包名           
    mPackage[i] = pi.applicationInfo.loadLabel(manager)+"\n"+pi.packageName;
    i++;          
 }
//Uri类型
NdefRecord recordUri = NdefRecord.createUri(Uri.parse("www.baidu.com"));

//创建NdefMessage,并将以上的NdefRecord添加进来,写入的NdefRecord可以是任意一条,也可以是多条
NdefMessage message = new NdefMessagge(new NdefRecord[]{recordText,recordPack,recordUri);

//将NdefMessage写进标签中
//获得写入大小
int size = ndefMessage.toByteArray().length;
//判断是否是NDEF标签
try {                
    if(ndef != null) {
        //说明是NDEF标签,开始连接
        ndef.connect();                    
        //判断是否可写
        if(!ndef.isWritable()){
            Toast.makeText(this, "当前设备不支持写入",Toast.LENGTH_LONG).show();
            ndef.close();
            return;
         }
        //获取标签的容量大小,判断是否足够写入
        if(ndef.getMaxSize() < size){
            Toast.makeText(this, "容量不足",Toast.LENGTH_LONG).show();
            ndef.close();
            return;
        }
        //写入
         try {
             //使用该方法将ndefmessage写进标签
             ndef.writeNdefMessage(ndefMessage);
             Toast.makeText(this, "写入成功",Toast.LENGTH_LONG).show();
             ndef.close();
         } catch (FormatException e) {
             e.printStackTrace();
         }
    }
} catch (IOException e) {
     e.printStackTrace();
}

以上就是在安卓系统上的nfc功能的使用,可以通过设置标签的内容实现某种功能,如将某一应用程序的包名写进标签,在标签靠近安卓板后,系统会自动打开该应用程序。

猜你喜欢

转载自blog.csdn.net/WQFAE01/article/details/79060819
今日推荐