0
点赞
收藏
分享

微信扫一扫

nfc开发


Android NFC开发环境

       使用硬件:Google Nexus S,北京大学学生卡。(ps:笔者本想使用公交一卡通进行测试,发现手机不能正确识别)

       手机操作系统:Android ICS 4.04。

       开发时,笔者从Google Play Store上下载了NFC TagInfo软件进行对比学习。所以我们可以使用任意一张能被TagInfo软件正确识别的卡做测试。

       在Android NFC 应用中,Android手机通常是作为通信中的发起者,也就是作为各种NFC卡的读写器。Android对NFC的支持主要在 android.nfc 和android.nfc.tech 两个包中。

       android.nfc 包中主要类如下:

       NfcManager 可以用来管理Android设备中指出的所有NFCAdapter,但由于大部分Android设备只支持一个NFC Adapter,所以一般直接调用getDefaultAapater来获取手机中的Adapter。

       NfcAdapter 相当于一个NFC适配器,类似于电脑装了网络适配器才能上网,手机装了NfcAdapter才能发起NFC通信。

       NDEF: NFC Data Exchange Format,即NFC数据交换格式。

       NdefMessage 和NdefRecord NDEF 为NFC forum 定义的数据格式。

       Tag 代表一个被动式Tag对象,可以代表一个标签,卡片等。当Android设备检测到一个Tag时,会创建一个Tag对象,将其放在Intent对象,然后发送到相应的Activity。

android.nfc.tech 中则定义了可以对Tag进行的读写操作的类,这些类按照其使用的技术类型可以分成不同的类如:NfcA, NfcB, NfcF,以及MifareClassic 等。其中MifareClassic比较常见。

       在本次实例中,笔者使用北京大学学生卡进行数据读取测试,学生卡的TAG类型为MifareClassic。

NFC开发实例讲解

        AndroidManifest.​​xml​​:


XML/HTML代码



    1. <span style="font-size:16px;"><?xml version="1.0" encoding="utf-8"?>
    2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"
    3. package="org.reno"
    4. android:versionCode="1"
    5. android:versionName="1.0" >
    6. <uses-permission android:name="android.permission.NFC" />
    7. <uses-sdk android:minSdkVersion="14" />
    8. <uses-feature android:name="android.hardware.nfc" android:required="true" />
    9. <application
    10. android:icon="@drawable/ic_launcher"
    11. android:label="@string/app_name" >
    12. <activity
    13. android:name="org.reno.Beam"
    14. android:label="@string/app_name"
    15. android:launchMode="singleTop" >
    16. <intent-filter>
    17. <action android:name="android.intent.action.MAIN" />
    18.
    19. <category android:name="android.intent.category.LAUNCHER" />
    20. </intent-filter>
    21. <intent-filter>
    22. <action android:name="android.nfc.action.TECH_DISCOVERED" />
    23. </intent-filter>
    24. <meta-data
    25. android:name="android.nfc.action.TECH_DISCOVERED"
    26. android:resource="@xml/nfc_tech_filter" />
    27. </activity>
    28. </application>
    29. </manifest>
    30. </span>


           res/xml/nfc_tech_filter.xml:


    XML/HTML代码


    1. <resourcesxmlns:xliffresourcesxmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    2. <tech-list>
    3. <tech>android.nfc.tech.MifareClassic</tech>
    4. </tech-list>
    5. </resources>
    6.
    7. <uses-permission android:name="android.permission.NFC"/>
    8. <uses-feature android:name="android.hardware.nfc" android:required="true"/>


           表示会使用到硬件的NFC功能。并且当用户在Google Play Store中搜索时,只有带有NFC功能的手机才能够搜索到本应用。

           当手机开启了NFC,并且检测到一个TAG后,TAG分发系统会自动创建一个封装了NFC TAG信息的​​intent​​​。如果多于一个应用程序能够处理这个intent的话,那么手机就会弹出一个框,让用户选择处理该TAG的​​Activity​​。TAG分发系统定义了3中intent。按优先级从高到低排列为:

           NDEF_DISCOVERED, TECH_DISCOVERED, TAG_DISCOVERED

           当Android设备检测到有NFC Tag靠近时,会根据Action申明的顺序给对应的Activity 发送含NFC消息的 Intent。

           此处我们使用的intent-filter的Action类型为TECH_DISCOVERED从而可以处理所有类型为ACTION_TECH_DISCOVERED并且使用的技术为nfc_tech_filter.xml文件中定义的类型的TAG。

           下图为当手机检测到一个TAG时,启用Activity的匹配过程。

    nfc开发_html

           res/layout/main.xml:


    XML/HTML代码



      1. <?xml version="1.0" encoding="utf-8"?>
      2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
      3. android:layout_width="fill_parent"
      4. android:layout_height="fill_parent"
      5. android:orientation="vertical" >
      6.
      7. <ScrollView
      8. android:id="@+id/scrollView"
      9. android:layout_width="fill_parent"
      10. android:layout_height="fill_parent"
      11. android:background="@android:drawable/edit_text" >
      12.
      13. <TextView
      14. android:id="@+id/promt"
      15. android:layout_width="fill_parent"
      16. android:layout_height="wrap_content"
      17. android:scrollbars="vertical"
      18. android:singleLine="false"
      19. android:text="@string/info" />
      20. </ScrollView>
      21.
      22. </LinearLayout>


             定义了Activity的布局:只有一个带有滚动条的​​TextView​​用于显示从TAG中读取的信息。

             res/values/strings.xml:


      XML/HTML代码


      1. <?xml version="1.0" encoding="utf-8"?>
      2. <resources>
      3. <string name="app_name">NFC测试</string>
      4. <string name="info">扫描中。。。</string>
      5. </resources>

             src/org/reno/Beam.java:


      Java代码


      1. package
      2.
      3. import
      4. import
      5. import
      6. import
      7. import
      8. import
      9. import
      10.
      11. public class Beam extends
      12. NfcAdapter nfcAdapter;
      13. TextView promt;
      14. @Override
      15. public void
      16. super.onCreate(savedInstanceState);
      17. setContentView(R.layout.main);
      18. promt = (TextView) findViewById(R.id.promt);
      19. // 获取默认的NFC控制器
      20. this);
      21. if (nfcAdapter == null) {
      22. "设备不支持NFC!");
      23. finish();
      24. return;
      25. }
      26. if
      27. "请在系统设置中先启用NFC功能!");
      28. finish();
      29. return;
      30. }
      31. }
      32.
      33. @Override
      34. protected void
      35. super.onResume();
      36. //得到是否检测到ACTION_TECH_DISCOVERED触发
      37. if
      38. //处理该intent
      39. processIntent(getIntent());
      40. }
      41. }
      42. //字符序列转换为16进制字符串
      43. private String bytesToHexString(byte[] src) {
      44. new StringBuilder("0x");
      45. if (src == null || src.length <= 0) {
      46. return null;
      47. }
      48. char[] buffer = new char[2];
      49. for (int i = 0; i < src.length; i++) {
      50. 0] = Character.forDigit((src[i] >>> 4) & 0x0F, 16);
      51. 1] = Character.forDigit(src[i] & 0x0F, 16);
      52. System.out.println(buffer);
      53. stringBuilder.append(buffer);
      54. }
      55. return
      56. }
      57.
      58. /**
      59. * Parses the NDEF Message from the intent and prints to the TextView
      60. */
      61. private void
      62. //取出封装在intent中的TAG
      63. Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
      64. for
      65. System.out.println(tech);
      66. }
      67. boolean auth = false;
      68. //读取TAG
      69. MifareClassic mfc = MifareClassic.get(tagFromIntent);
      70. try
      71. "";
      72. //Enable I/O operations to the tag from this TagTechnology object.
      73. mfc.connect();
      74. int type = mfc.getType();//获取TAG的类型
      75. int sectorCount = mfc.getSectorCount();//获取TAG中包含的扇区数
      76. "";
      77. switch
      78. case
      79. "TYPE_CLASSIC";
      80. break;
      81. case
      82. "TYPE_PLUS";
      83. break;
      84. case
      85. "TYPE_PRO";
      86. break;
      87. case
      88. "TYPE_UNKNOWN";
      89. break;
      90. }
      91. "卡片类型:" + typeS + "\n共" + sectorCount + "个扇区\n共"
      92. "个块\n存储空间: " + mfc.getSize() + "B\n";
      93. for (int j = 0; j < sectorCount; j++) {
      94. //Authenticate a sector with key A.
      95. auth = mfc.authenticateSectorWithKeyA(j,
      96. MifareClassic.KEY_DEFAULT);
      97. int
      98. int
      99. if
      100. "Sector " + j + ":验证成功\n";
      101. // 读取扇区中的块
      102. bCount = mfc.getBlockCountInSector(j);
      103. bIndex = mfc.sectorToBlock(j);
      104. for (int i = 0; i < bCount; i++) {
      105. byte[] data = mfc.readBlock(bIndex);
      106. "Block " + bIndex + " : "
      107. "\n";
      108. bIndex++;
      109. }
      110. else
      111. "Sector " + j + ":验证失败\n";
      112. }
      113. }
      114. promt.setText(metaInfo);
      115. catch
      116. e.printStackTrace();
      117. }
      118. }
      119. }

             关于MifareClassic卡的背景介绍:数据分为16个区(Sector) ,每个区有4个块(Block) ,每个块可以存放16字节的数据。

             每个区最后一个块称为Trailer ,主要用来存放读写该区Block数据的Key ,可以有A,B两个Key,每个Key 长度为6个字节,缺省的Key值一般为全FF或是0。由MifareClassic.KEY_DEFAULT 定义。

             因此读写Mifare Tag 首先需要有正确的Key值(起到保护的作用),如果鉴权成功,然后才可以读写该区数据。

             执行效果:

      nfc开发_android_02

      nfc开发_html_03

      nfc开发_xml_04

      举报

      相关推荐

      0 条评论