android NFC开发

先说说NFC开发总结,看了几天NFC开发资料,搜集了不少关于这方面的资料、demo、以及他人的总结。以下有部分是摘录总结的。因为要是现在总结也是那些,最后附送代码。关于demo我也有,有需要在评论去发邮箱给我。

一、NFC的配置总结

第一:屏幕没有锁住 。     第二:NFC功能已经在设置中打开
当系统检测到一个NFC标签的时候,他会自动去寻找最合适的activity去处理这个intent.
NFC发出的这个Intent将会有三种action:
ACTION_NDEF_DISCOVERED:当系统检测到tag中含有NDEF格式的数据时,且系统中有activity声明可以接受包含NDEF数据的Intent的时候,系统会优先发出这个action的intent。

ACTION_TECH_DISCOVERED:当没有任何一个activity声明自己可以响应ACTION_NDEF_DISCOVERED时,系统会尝试发出TECH的intent.即便你的tag中所包含的数据是NDEF的,但是如果这个数据的MIMEtype或URI不能和任何一个activity所声明的想吻合,系统也一样会尝试发出tech格式的intent,而不是NDEF.

ACTION_TAG_DISCOVERED:当系统发现前两个intent在系统中无人会接受的时候,就只好发这个默认的TAG类型的


二、NFC相关androidManifest文件设置

首先是权限:
<uses-permissionandroid:name="Android.permission.NFC"/>

然后是sdk级别限制:我个人建议API11开始比较合适:
<uses-sdkandroid:minSdkVersion="11"/>

如果是API8,在代码中,nfc功能设置的代码会出错,要抛出
例如:
  NfcAdapter mAdapter = NfcAdapter.getDefaultAdapter(this);
  mAdapter.isEnabled()

接着是特殊功能限制:
<uses-featureandroid:name="Android.hardware.nfc"android:required="true"/>这个生命可以让你的应用在googleplay上被声明使用者必须拥有nfc功能。


三、NFC标签过滤,也在androidManifest文件设置

在activity的intent过滤xml声明中,你可以同时声明过滤这三种action.但是由之前所说,你应该知道系统在发送intent的时候是有优先级的,所以你最好清楚自己最想处理哪个。

1:过滤ACTION_TAG_DISCOVERED:

[html]  view plain  copy
  1. <intent-filter>  
  2.     <action android:name="android.nfc.action.TAG_DISCOVERED"/>  
  3.     <category android:name="android.intent.category.DEFAULT"/>  
  4. </intent-filter>  
这个最简单,也是最后一个被尝试接受intent的选项。

2:过滤ACTION_NDEF_DISCOVERED:

[html]  view plain  copy
  1. <intent-filter>   
  2. <action android:name="android.nfc.action.NDEF_DISCOVERED"/>   
  3. <category android:name="android.intent.category.DEFAULT"/>   
  4. <data android:mimeType="text/plain" />  
  5.  </intent-filter>  
其中最重要的应该算是data的mimeType类型了,这个定义的越准确,intent指向你这个activity的成功率就越高,否则系统可能不会发出你想要的NDEF intent了。下面在讲如何使用NDEF写入NFC标签的时候会多举几个类型的例子。


3:过滤ACTION_TECH_DISCOVERED:

你首先需要在你的<project-path>/res/xml下面创建一个过滤规则文件。名字任取,比如可以叫做nfc_tech_filter.xml。这个里面定义的是nfc实现的各种标准,每一个nfc卡都会符合多个不同的标准,个人理解为这些标准有些相互之间也是兼容的。你可以在检测到nfc标签后使用getTechList()方法来查看你所检测的tag到底支持哪些nfc标准。
一个nfc_tech_filter.xml中可以定义多个<tech-list>结构组。

[html]  view plain  copy
  1. <span style="font-size:18px;"><resources xmlns:xliff="urn:oasis:names:tc:xliff:documen</span>t:1.2">  
  2. <tech-list>   
  3. <tech>  
  4. android.nfc.tech.IsoDep</tech>  
  5.  <tech>android.nfc.tech.NfcA</tech>   
  6.   <tech>android.nfc.tech.NfcB</tech>   
  7. <tech>android.nfc.tech.NfcF</tech>   
  8. </tech-list>  
  9. <tech-list>  
  10. <tech>android.nfc.tech.NfcV</tech>   
  11. <tech>android.nfc.tech.Ndef</tech>   
  12. <tech>android.nfc.tech.NdefFormatable</tech>  
  13.  <tech>android.nfc.tech.MifareClassic</tech>   
  14. <tech>android.nfc.tech.MifareUltralight</tech>  
  15.  </tech-list>   
  16. </resources>  

在androidManifest文件中声明xml过滤的举例如下:

[html]  view plain  copy
  1. <activity>   
  2.  <intent-filter>   
  3. <action android:name="android.nfc.action.TECH_DISCOVERED"/>   
  4. </intent-filter>   
  5. <meta-data android:name="android.nfc.action.TECH_DISCOVERED"        
  6. android:resource="@xml/nfc_tech_filter" />  
  7.  </activity>  

四、看具体代码:

1、主要代码实现如下:

[java]  view plain  copy
  1. package org.reno.Beam;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.nio.charset.Charset;  
  5. import java.text.DateFormat;  
  6. import java.text.SimpleDateFormat;  
  7. import java.util.Date;  
  8. import java.util.List;  
  9. import java.util.Locale;  
  10. import org.nfc.read.ParsedNdefRecord;  
  11. import android.app.Activity;  
  12. import android.app.AlertDialog;  
  13. import android.app.PendingIntent;  
  14. import android.content.DialogInterface;  
  15. import android.content.Intent;  
  16. import android.nfc.NdefMessage;  
  17. import android.nfc.NdefRecord;  
  18. import android.nfc.NfcAdapter;  
  19. import android.nfc.Tag;  
  20. import android.nfc.tech.MifareClassic;  
  21. import android.nfc.tech.MifareUltralight;  
  22. import android.os.Bundle;  
  23. import android.os.Parcelable;  
  24. import android.provider.Settings;  
  25. import android.widget.TextView;  
  26.   
  27. public class MainActivity extends Activity {  
  28.     private static final DateFormat TIME_FORMAT = SimpleDateFormat  
  29.             .getDateTimeInstance();  
  30.     private NfcAdapter mAdapter;  
  31.     private PendingIntent mPendingIntent;  
  32.     private NdefMessage mNdefPushMessage;  
  33.     private TextView promt;  
  34.     private AlertDialog mDialog;  
  35.   
  36.     @Override  
  37.     public void onCreate(Bundle savedInstanceState) {  
  38.         super.onCreate(savedInstanceState);  
  39.         setContentView(R.layout.activity_main);  
  40.         promt = (TextView) findViewById(R.id.promt);  
  41.   
  42.         resolveIntent(getIntent());  
  43.   
  44.         mDialog = new AlertDialog.Builder(this).setNeutralButton("Ok"null)  
  45.                 .create();  
  46.         // 获取默认的NFC控制器  
  47.         mAdapter = NfcAdapter.getDefaultAdapter(this);  
  48.   
  49.         //拦截系统级的NFC扫描,例如扫描蓝牙  
  50.         mPendingIntent = PendingIntent.getActivity(this0new Intent(this,  
  51.                 getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);  
  52.         mNdefPushMessage = new NdefMessage(new NdefRecord[] { newTextRecord("",  
  53.                 Locale.ENGLISH, true) });  
  54.     }  
  55.   
  56.     @Override  
  57.     protected void onResume() {  
  58.         super.onResume();  
  59.         if (mAdapter == null) {  
  60.             if (!mAdapter.isEnabled()) {  
  61.                 showWirelessSettingsDialog();  
  62.             }  
  63.   
  64.             showMessage(R.string.error, R.string.no_nfc);  
  65.             promt.setText("设备不支持NFC!");  
  66.             return;  
  67.         }  
  68.         if (!mAdapter.isEnabled()) {  
  69.             promt.setText("请在系统设置中先启用NFC功能!");  
  70.             return;  
  71.         }  
  72.   
  73.         if (mAdapter != null) {  
  74.             //隐式启动  
  75.             mAdapter.enableForegroundDispatch(this, mPendingIntent, nullnull);  
  76.             mAdapter.enableForegroundNdefPush(this, mNdefPushMessage);  
  77.         }  
  78.     }  
  79.   
  80.     @Override  
  81.     protected void onPause() {  
  82.         super.onPause();  
  83.         if (mAdapter != null) {  
  84.             //隐式启动  
  85.             mAdapter.disableForegroundDispatch(this);  
  86.             mAdapter.disableForegroundNdefPush(this);  
  87.         }  
  88.     }  
  89.   
  90.     //16进制字符串转换为String  
  91.     private String hexString = "0123456789ABCDEF";  
  92.     public String decode(String bytes) {  
  93.         if (bytes.length() != 30) {  
  94.             return null;  
  95.         }  
  96.         ByteArrayOutputStream baos = new ByteArrayOutputStream(  
  97.                 bytes.length() / 2);  
  98.         // 将每2位16进制整数组装成一个字节  
  99.         for (int i = 0; i < bytes.length(); i += 2)  
  100.             baos.write((hexString.indexOf(bytes.charAt(i)) << 4 | hexString  
  101.                     .indexOf(bytes.charAt(i + 1))));  
  102.         return new String(baos.toByteArray());  
  103.     }  
  104.   
  105.     // 字符序列转换为16进制字符串  
  106.     private static String bytesToHexString(byte[] src, boolean isPrefix) {  
  107.         StringBuilder stringBuilder = new StringBuilder();  
  108.         if (isPrefix == true) {  
  109.             stringBuilder.append("0x");  
  110.         }  
  111.         if (src == null || src.length <= 0) {  
  112.             return null;  
  113.         }  
  114.         char[] buffer = new char[2];  
  115.         for (int i = 0; i < src.length; i++) {  
  116.             buffer[0] = Character.toUpperCase(Character.forDigit(  
  117.                     (src[i] >>> 4) & 0x0F16));  
  118.             buffer[1] = Character.toUpperCase(Character.forDigit(src[i] & 0x0F,  
  119.                     16));  
  120.             System.out.println(buffer);  
  121.             stringBuilder.append(buffer);  
  122.         }  
  123.         return stringBuilder.toString();  
  124.     }  
  125.   
  126.     private void showMessage(int title, int message) {  
  127.         mDialog.setTitle(title);  
  128.         mDialog.setMessage(getText(message));  
  129.         mDialog.show();  
  130.     }  
  131.   
  132.     private NdefRecord newTextRecord(String text, Locale locale,  
  133.             boolean encodeInUtf8) {  
  134.         byte[] langBytes = locale.getLanguage().getBytes(  
  135.                 Charset.forName("US-ASCII"));  
  136.   
  137.         Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset  
  138.                 .forName("UTF-16");  
  139.         byte[] textBytes = text.getBytes(utfEncoding);  
  140.   
  141.         int utfBit = encodeInUtf8 ? 0 : (1 << 7);  
  142.         char status = (char) (utfBit + langBytes.length);  
  143.   
  144.         byte[] data = new byte[1 + langBytes.length + textBytes.length];  
  145.         data[0] = (byte) status;  
  146.         System.arraycopy(langBytes, 0, data, 1, langBytes.length);  
  147.         System.arraycopy(textBytes, 0, data, 1 + langBytes.length,  
  148.                 textBytes.length);  
  149.   
  150.         return new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT,  
  151.                 new byte[0], data);  
  152.     }  
  153.   
  154.     private void showWirelessSettingsDialog() {  
  155.         AlertDialog.Builder builder = new AlertDialog.Builder(this);  
  156.         builder.setMessage(R.string.nfc_disabled);  
  157.         builder.setPositiveButton(android.R.string.ok,  
  158.                 new DialogInterface.OnClickListener() {  
  159.                     public void onClick(DialogInterface dialogInterface, int i) {  
  160.                         Intent intent = new Intent(  
  161.                                 Settings.ACTION_WIRELESS_SETTINGS);  
  162.                         startActivity(intent);  
  163.                     }  
  164.                 });  
  165.         builder.setNegativeButton(android.R.string.cancel,  
  166.                 new DialogInterface.OnClickListener() {  
  167.                     public void onClick(DialogInterface dialogInterface, int i) {  
  168.                         finish();  
  169.                     }  
  170.                 });  
  171.         builder.create().show();  
  172.         return;  
  173.     }  
  174.   
  175.     //初步判断是什么类型NFC卡  
  176.     private void resolveIntent(Intent intent) {  
  177.         String action = intent.getAction();  
  178.         if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)  
  179.                 || NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)  
  180.                 || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {  
  181.             Parcelable[] rawMsgs = intent  
  182.                     .getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);  
  183.             NdefMessage[] msgs;  
  184.             if (rawMsgs != null) {  
  185.                 msgs = new NdefMessage[rawMsgs.length];  
  186.                 for (int i = 0; i < rawMsgs.length; i++) {  
  187.                     msgs[i] = (NdefMessage) rawMsgs[i];  
  188.                 }  
  189.             } else {  
  190.                 // Unknown tag type  
  191.                 byte[] empty = new byte[0];  
  192.                 byte[] id = intent.getByteArrayExtra(NfcAdapter.EXTRA_ID);  
  193.                 Parcelable tag = intent  
  194.                         .getParcelableExtra(NfcAdapter.EXTRA_TAG);  
  195.                 byte[] payload = dumpTagData(tag).getBytes();  
  196.                 NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN,  
  197.                         empty, id, payload);  
  198.                 NdefMessage msg = new NdefMessage(new NdefRecord[] { record });  
  199.                 msgs = new NdefMessage[] { msg };  
  200.             }  
  201.             // Setup the views  
  202.             buildTagViews(msgs);  
  203.         }  
  204.     }  
  205.   
  206.     //一般公家卡,扫描的信息  
  207.     private String dumpTagData(Parcelable p) {  
  208.         StringBuilder sb = new StringBuilder();  
  209.         Tag tag = (Tag) p;  
  210.         byte[] id = tag.getId();  
  211.         sb.append("Tag ID (hex): ").append(getHex(id)).append("\n");  
  212.         sb.append("Tag ID (dec): ").append(getDec(id)).append("\n");  
  213.         sb.append("ID (reversed): ").append(getReversed(id)).append("\n");  
  214.   
  215.         String prefix = "android.nfc.tech.";  
  216.         sb.append("Technologies: ");  
  217.         for (String tech : tag.getTechList()) {  
  218.             sb.append(tech.substring(prefix.length()));  
  219.             sb.append(", ");  
  220.         }  
  221.         sb.delete(sb.length() - 2, sb.length());  
  222.         for (String tech : tag.getTechList()) {  
  223.             if (tech.equals(MifareClassic.class.getName())) {  
  224.                 sb.append('\n');  
  225.                 MifareClassic mifareTag = MifareClassic.get(tag);  
  226.                 String type = "Unknown";  
  227.                 switch (mifareTag.getType()) {  
  228.                 case MifareClassic.TYPE_CLASSIC:  
  229.                     type = "Classic";  
  230.                     break;  
  231.                 case MifareClassic.TYPE_PLUS:  
  232.                     type = "Plus";  
  233.                     break;  
  234.                 case MifareClassic.TYPE_PRO:  
  235.                     type = "Pro";  
  236.                     break;  
  237.                 }  
  238.                 sb.append("Mifare Classic type: ");  
  239.                 sb.append(type);  
  240.                 sb.append('\n');  
  241.   
  242.                 sb.append("Mifare size: ");  
  243.                 sb.append(mifareTag.getSize() + " bytes");  
  244.                 sb.append('\n');  
  245.   
  246.                 sb.append("Mifare sectors: ");  
  247.                 sb.append(mifareTag.getSectorCount());  
  248.                 sb.append('\n');  
  249.   
  250.                 sb.append("Mifare blocks: ");  
  251.                 sb.append(mifareTag.getBlockCount());  
  252.             }  
  253.   
  254.             if (tech.equals(MifareUltralight.class.getName())) {  
  255.                 sb.append('\n');  
  256.                 MifareUltralight mifareUlTag = MifareUltralight.get(tag);  
  257.                 String type = "Unknown";  
  258.                 switch (mifareUlTag.getType()) {  
  259.                 case MifareUltralight.TYPE_ULTRALIGHT:  
  260.                     type = "Ultralight";  
  261.                     break;  
  262.                 case MifareUltralight.TYPE_ULTRALIGHT_C:  
  263.                     type = "Ultralight C";  
  264.                     break;  
  265.                 }  
  266.                 sb.append("Mifare Ultralight type: ");  
  267.                 sb.append(type);  
  268.             }  
  269.         }  
  270.   
  271.         return sb.toString();  
  272.     }  
  273.   
  274.     private String getHex(byte[] bytes) {  
  275.         StringBuilder sb = new StringBuilder();  
  276.         for (int i = bytes.length - 1; i >= 0; --i) {  
  277.             int b = bytes[i] & 0xff;  
  278.             if (b < 0x10)  
  279.                 sb.append('0');  
  280.             sb.append(Integer.toHexString(b));  
  281.             if (i > 0) {  
  282.                 sb.append(" ");  
  283.             }  
  284.         }  
  285.         return sb.toString();  
  286.     }  
  287.   
  288.     private long getDec(byte[] bytes) {  
  289.         long result = 0;  
  290.         long factor = 1;  
  291.         for (int i = 0; i < bytes.length; ++i) {  
  292.             long value = bytes[i] & 0xffl;  
  293.             result += value * factor;  
  294.             factor *= 256l;  
  295.         }  
  296.         return result;  
  297.     }  
  298.   
  299.     private long getReversed(byte[] bytes) {  
  300.         long result = 0;  
  301.         long factor = 1;  
  302.         for (int i = bytes.length - 1; i >= 0; --i) {  
  303.             long value = bytes[i] & 0xffl;  
  304.             result += value * factor;  
  305.             factor *= 256l;  
  306.         }  
  307.         return result;  
  308.     }  
  309.   
  310.     //显示NFC扫描的数据  
  311.     private void buildTagViews(NdefMessage[] msgs) {  
  312.         if (msgs == null || msgs.length == 0) {  
  313.             return;  
  314.         }  
  315.         // Parse the first message in the list  
  316.         // Build views for all of the sub records  
  317.         Date now = new Date();  
  318.         List<ParsedNdefRecord> records = NdefMessageParser.parse(msgs[0]);  
  319.         final int size = records.size();  
  320.         for (int i = 0; i < size; i++) {  
  321.             TextView timeView = new TextView(this);  
  322.             timeView.setText(TIME_FORMAT.format(now));  
  323.             ParsedNdefRecord record = records.get(i);  
  324.             promt.append(record.getViewText());  
  325.         }  
  326.     }  
  327.   
  328.     //获取系统隐式启动的  
  329.     @Override  
  330.     public void onNewIntent(Intent intent) {  
  331.         setIntent(intent);  
  332.         resolveIntent(intent);  
  333.     }  
  334. }  

2、androidManifest配置

[html]  view plain  copy
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="org.reno.Beam"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.   
  7.     <uses-sdk  
  8.         android:minSdkVersion="11"  
  9.         android:targetSdkVersion="16" />  
  10.   
  11.     <!-- 权限 -->  
  12.     <uses-permission android:name="android.permission.NFC" />  
  13.   
  14.     <!-- 是否支持谷歌什么硬件一般可以忽略 -->  
  15.     <uses-feature android:name="android.hardware.nfc" />  
  16.   
  17.     <application  
  18.         android:allowBackup="true"  
  19.         android:icon="@drawable/ic_launcher"  
  20.         android:label="@string/app_name"  
  21.         android:theme="@style/AppTheme" >  
  22.         <activity  
  23.             android:name="org.reno.Beam.MainActivity"  
  24.             android:alwaysRetainTaskState="true"  
  25.             android:label="@string/app_name"  
  26.             android:launchMode="singleInstance"  
  27.             android:screenOrientation="nosensor" >  
  28.             <intent-filter>  
  29.                 <action android:name="android.intent.action.MAIN" />  
  30.   
  31.                 <category android:name="android.intent.category.LAUNCHER" />  
  32.             </intent-filter>  
  33.             <intent-filter>  
  34.                 <action android:name="android.nfc.action.TECH_DISCOVERED" />  
  35.                 <!-- 添加这一条默认设置,能拦截当前页面所有扫描NFC的配置 -->  
  36.                 <category android:name="android.intent.category.DEFAULT" />  
  37.             </intent-filter>  
  38.   
  39.             <!--  
  40.                   这个过滤条件我就没有使用了  
  41.                 <meta-data  
  42.                 android:name="android.nfc.action.TECH_DISCOVERED"  
  43.                 android:resource="@xml/nfc_tech_filter" />  
  44.             -->  
  45.         </activity>  
  46.     </application>  
  47.   
  48. </manifest> 

  49. 本文的下载地址demo:http://download.csdn.net/detail/qq_16064871/9324211

猜你喜欢

转载自blog.csdn.net/u010025003/article/details/72354400