Android 学习操作NFC(1)

来源:互联网 发布:php网上商城教学日志 编辑:程序博客网 时间:2024/05/19 16:32




在研读了WP8 – Proximity APIs之后撰写了几篇文章,深深觉得NFC非常有趣,进一步希望了解Android在这一块的处理方式,因此,补上了该篇介绍一下自己在学习Android处理NFC时的心得。
 
〉概要
     在Android系统下,目前主要以支持NDEF NFC Data Exchange Format (NDEF)格式为主,它支持devices之间或device与tag之间互相交换小型payload的数据。由于是属于近距离的无线技术,典型是在4 cm或更接近时建立联机。
单一个tag就具有多种交易的方式,包括:read-only、加/解密、多种型式格式…等。但如果遇到是非预设支持的NDEF在Android仍有自订相关处理方式,往后进一步说明。
 
需注意的是:
     ‧Android 2.3.3 (API Level 10)才有支持完整的NFC功能;
     ‧Android 4.x 支持 Android Application Record (AAR);
     ‧Android 4.0 支持 Beam;
 
在Android developers官网里分别有二篇文章说明NFC的使用:<NFC Basics>与<Advanced NFC>。
本篇主要根据<NFC Basics>学习在Android上:
    ‧如何传送与接收NDEF data message;
        来自NFC tag 、 Beaming NDEF Message由一个device到另一个;
    ‧操作NFC APIs、Android Beam™;
 
NDFE data从NFC tag中取出,交由tag dispatch system进行处理,包括:分析发现的NFC tags、将数据进行分类,并且根据数据启动应用程序。一个应用程序想要处理被扫瞄到的NFC tag,可以宣告intent filter与请求要处理的data
 
Android Beam™功能允许一个device可发布NDEF message至另一个device,透过二个devices直接tapping。这样的方式比过去使用Bluetooth、Wi-Fi容易许多,因为不需要在配对或联机验证,只需二个devices接近至一定距离则自动触发。
Android Beam是经由NFC APIs所提供的功能,任何应用程序均能使用它在二个device之间传送数据,例如:分享联络人、web pages、videos…等。
 
有了一些Android在处理NFC tag与APIs的概论之后,往下进一步讨论当取得NFC tag中的数据时,要如何识别它是那种类型,以及具有那些特殊的识别标签与储存的方式。
 
 
〉The Tag Dispatch System
     在Android系统中,如果有开启NFC的功能,当设备屏幕锁定时,NFC功能会被取消,直到设备被唤醒后,NFC功能才会启动。
达到省电的效果。当Android-powered device发现一个NFC tag,最好的作法是自动启动对应的应用程序,而不是询问用户选择
为什么会这样说呢?因为设备扫瞄NFC tags在非常近的距离,尤其是在背靠背时,要用户移动手机回到前面选择要启动的程序有可能因为移动Tags或Devices离开了联机,非常不方便。因此,你应该开发让你的Activity只处理您在乎的NFC tags,以防止出现Activity Chooser要用户选择。
 
为了达到上述的目标,Android提供了tag dispatch system协助分析发现的NFC tags、剖析它们,并尝式指定启动特定应用程序。
主要做的事情,如下:
(1) 拆解NFC tag与搞清除是MIME type或URI的数据payload储存于tag中;
(2) 封装MIME type或URI的数据payload至intent object中;
(3) 基于建立好的intent object启动activity;
 
这三件事也就是Android处理NFC tags/devices之间的重要流程,往下逐一说明(1)与(2),加上(3)的各自处理方式。
 
 
〉How NFC tags are mapped to MIME types and URIs
     在开发NFC application之前一定要先了解有多少种NFC tag类型、tag dispatch system如何剖析它们,以及当读取到一个NDFE message时要执行那些动作。相对的,如果要写入NDEF message至devices或tag也有很多种方式要特别注意。
然而,Android支持大部分NDEF标准,而这些NDEF标准由NFC Forum所定义,相关的文献如下:
<NFC Forum Specification Download>完整说明NFC的tag规格与<Creating common types of NDEF records>说明建立NDEF record。
 
‧NFC tag结构
    NFC tag中的NDEF数据被封装于NFC message里,其NFC message内可有1~N个records(NdefRecord),每一个NDEF record必需是符合标准定义所建立而成。Android支持其它类型的tags,它们可能不包含NDEF data,如果要操作它可以使用android.nfc.tech下的类别进行处理,相关的信息可参考<Advanced NFC>。
 
有了基本NDEF tags的背景后,由于当发现一个NFC tag包含NDEF Formatted data,它将开始剖析并识别是否为MIME type或URI。
做剖析与识别,需从NDEF message中的第一个NdefRecord中,识别它为何种数据类型,往下了解NDEF record的定义:
 
a. the First record (NdefRecord)
     由四个信息组合:
1). 3-bit TNF (Type Name Format)
      说明如何解释Type字段 (Variable length type)的格式。透过下表说明the tag dispatch system如何透过TNF与type field      来识别该NDEF message是MIME type或URI。可以被配对到的NDEF message,系统会触发ACTION_NDEF_DISCOVERED,      如果无法配对,系统会再倒给ACTION_TECH_DISCOVERED进行配对,如果没有再退给ACTION_TAG_DISCOVERED。
 
2). Variable length type
      描述该record的类型。如果是TNF_WELL_KNOWN,使用该字段需要参考Record Type Definition (RTD)。
 
3). Variable length ID
      该record的unique identifier。该字段经常不使用,但如果需要唯一识别该tag,可以建立一个ID给他。
 
4). Variable length payload
      实际想要读或写的数据内容(data payload)。一个NDEF message可包括多个NDEF records,所以不要以为所有的数据均写在NDEF message的第一个record。www.it165.net
 
the tag dispatch system透过TNF与type field尝试去配对NDEF message符合MIME type或URI。如果配对成功,系统会封装这些信息至ACTION_NDEF_DISCOVERED intent,以及包括实际的data payload。然而,如何遇到无法配对或是NFC tag不包含NDEF data造成无法配对,系统会再倒给ACTION_TECH_DISCOVERED进行配对,如果没有再退给ACTION_TAG_DISCOVERED。
 
以下来了解TNF具有那些类型,以及当TNF为TNF_WELL_KNOWN时搭配RTD有那些:

Type Name Format (TNF)MappingTNF_ABSOLUTE_URIType字段数据格式为:URI。TNF_EMPTYAndroid系统触发ACTION_TECH_DISCOVERED的方式处理。TNF_EXTERNAL_TYPEType字段数据格式为:URN类型的URI。 URN被编码放入NDEF type字段,符合一个字段格式:<domain name>:<service name>
Android系统转译成:vnd.android.nfc://ext/<domain name>:<service name>。TNF_MIME_MEDIAType字段数据格式为:MIME。TNF_UNCHANGED第一个record为无效的,Android触发ACTION_TECH_DISCOVERED的方式处理。TNF_UNKNOWNAndroid触发ACTION_TECH_DISCOVERED的方式处理。TNF_WELL_KNOWN设定在type field中的MIME type或URI,是取决于Record Type Definition (RTD)。      如果TNF值为:TNF_WELL_KNOWN,则会相关RTD的格式可再透过下表来看:
Record Type Definition (RTD)MappingRTD_ALTERNATIVE_CARRIERFalls back to ACTION_TECH_DISCOVERED.RTD_HANDOVER_CARRIERFalls back to ACTION_TECH_DISCOVERED.RTD_HANDOVER_REQUESTFalls back to ACTION_TECH_DISCOVERED.RTD_HANDOVER_SELECTFalls back to ACTION_TECH_DISCOVERED.RTD_SMART_POSTERURI based on parsing the payload.RTD_TEXTMIME type of text/plain.RTD_URIURI based on payload. 
了解了如何识别该NDEF data message 为类型之后,接着往下说明当识别之后要怎么触发对应的处理与呼叫应用程序。
 
〉How NFC Tags are Dispatched to Applications
     当tag dispatch system建立一个intent里面封装了NFC tag与识别信息,它将传送给filters该intent的应用程序去处理。
如果有一个以上的应用程序处理该intent,Activity Chooser将呈现一个清单对话框让用户选择要执行的Activity。
tag dispatch system定义了三种intents,根据优先权由高至低进行排序
(1).  ACTION_NDEF_DISCOVERED
         当tag内容包括一个NDEF payload与具有可识别的类型被扫瞄到,该intent被用来启动一个Activity。
         这是最高的优先权,在往下交给其它的intent之前,tag dispatch system会尝试去开启并夹该intent启动一个Activity。
 
(2).  ACTION_TECH_DISCOVERED
         如果没有activities注册处理ACTION_NDEF_DISCOVERED该intent,tag dispatch system会发启一个ACTION_TECH_DISCOVER的         intent给对应的应用程序进行处理。
         tag dispatch system查觉该tag具有NDEF data但却没有对应至MIME type或URI,或是该tag没有包括NDEF data但是一个TNF_WELL_KNOWN的识别,它将会发启一个ACTION_TECH_DISCOVERED的intent (而不会启动ACTION_NDEF_DISCOVERED)。
 
(3).  ACTION_TAG_DISCOVERED
         如果没有activities注册处理ACTION_NDEF_DISCOVERED、ACTION_TECH_DISCOVERED的intents,将会发启该intent。
 
其本的tag dispatch system处理流程如下图:
 
\
 

1. 当处理到一个NFC tag时,tag dispatch system发出ACTION_NDEF_DISCOVERED或ACTION_TECH_DISCOVERED任一种,
    尝试去启动一个应用程序来处理该intent。
2. 如果没有应用程序filter这个intent,尝试再发出比较低顺序的ACTION_TECH_DISCOVERED或ACTION_TAG_DISCOVERED,
    直到有应用程序来处理该intent或tag dispatch system尝试所有可能的intents。
3. 如果没有任何应用程序filter任何的intents,则什么都不做。
 
 
以上介绍了Android在处理NFC Tag的机制,主要透过tag dispatch system来进行事件的触发与流程,往下将撰写范例程序
进行说明:
 
〉范例说明:
(1). 在AppManifest.xml中增加必要的uses-permission、最低的SDK版本、设定uses-feature:
     ‧指定uses-permission:

 

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

‧指定最低的SDK版本:

<uses-sdk android:minSdkVersion="10"/>

API Level 9虽也有支持NFC,但只限于支持ACTION_TAG_DISCOVERED与透过EXTRA_NDEF_MESSAGES取得NDEF Message。
由于完整的NFC功能从Android 2.3.3 (API Level 10)才开始支持,所以要记得宣告使用的最低SDK版本,因为API Level 10支持
Reader/Writer的功能;另外,API Level 14提供了更简单透过Android Beam进行Push NDEF Message至另一个设备,以及更方
便的方法建立NDEF records。
 
       ‧指定uses-feature:

 

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

指定该应用程序必需具有NFC芯片才能安装,如果设定android:required = true代表Google Play会自动过滤掉没有支持NFC芯片的设备,

这样一来,具有这些设备的用户将搜寻不到该应用程序。如果您的应用程序非以NFC为主要功能,可不设定该uses-feature或是将值

设定为false,改由程序中呼叫getDefaultAdapter()方法判断是否为null进行功能的限制。

 

 

(2). 设定Filtering for NFC Intents:

        为了让应用程序可以处理NFC Tag被扫瞄后所发出的Intents,应用程序需要在AppManifest.xml注册多个Filter来取得NFCT intents。

 

‧注册ACTION_NDEF_DISCOVERED:处理大部分NDEF Message;

‧注册ACTION_TECH_DISCOVERED:处理当没有应用程序处理ACTION_NDEF_DISCOVERED或该Tag非NDEF message所退回的intent;

‧注册ACTION_TAG_DISCOVERED:处理通常过于笼统的类别进行筛选。也就是上述二个intents除外的intent;

 

通常应用程序优先处理ACTION_NDEF_DISCOVERED、ACTION_TECH_DISCOVERED,除非这二个无法处理,最后才会轮到

ACTION_TAG_DISCOVERED。也因为ACTION_TAG_DISCOVERED可能侦测到的NFC Tag是比较特殊的格式,可以搭配<Advanced NFC>来做参考。

 

[注意]

由于NFC Tag部署有所不同,很多时候不是应用程序或系统所能控制之下,这并非不可能的,这就是为什么必要时tag dispatch system

可以回退到其它两个intents。当取得NFC Tag是有办法识别的类型,且具有数据写入的控制权,建议您使用的NDEF格式化标签。

 

(2-1). 注册filter ACTION_NDEF_DISCOVERED:

            为了filter ACTION_NDEF_DISCOVERED intents,宣告intent filter要处理的数据类型。

以下例子使用处理MIME Type为text/plain:

 

view sourceprint?
1.<intent-filter>
2.    <actionandroid:name="android.nfc.action.NDEF_DISCOVERED"/>
3.    <categoryandroid:name="android.intent.category.DEFAULT"/>
4.    <dataandroid:mimeType="text/plain"/>
5.</intent-filter>

以下例子使用处理URI类型:http://developer.android.com/index.html;

注册处理为http的scheme,developer.android.com的host,以及固定第一个字段为:index.html。

view sourceprint?
1.<intent-filter>
2.    <actionandroid:name="android.nfc.action.NDEF_DISCOVERED"/>
3.    <categoryandroid:name="android.intent.category.DEFAULT"/>
4.   <dataandroid:scheme="http"
5.              android:host="developer.android.com"
6.              android:pathPrefix="/index.html"/>
7.</intent-filter>

(2-2). 注册filter ACTION_TECH_DISCOVERED:

          如果要注册filter ACTION_TECH_DISCOVERED,需要在项目中增加一个新的XML档案,定义该应用程序支持的 tech-list sets。

可以透过呼叫getTechList()来确认侦测到的NFC tag是否与定义的tech-list sets有所匹配。该档案建议放罝于<project-root>/res/xml目录下。

举例来说:

如果一个tag被侦测到,它支持三种标准:MifareClassic、NdefFormatable与NfcA,在定义的tech-list sets就需要加入这些标准,

可能是一个、二个或三个标准都支持,以确保可以处理该intent。以下列出定义常见的tech-list集合:

 

view sourceprint?
01.<resourcesxmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
02.    <tech-list>
03.        <tech>android.nfc.tech.IsoDep</tech>
04.        <tech>android.nfc.tech.NfcA</tech>
05.        <tech>android.nfc.tech.NfcB</tech>
06.        <tech>android.nfc.tech.NfcF</tech>
07.        <tech>android.nfc.tech.NfcV</tech>
08.        <tech>android.nfc.tech.Ndef</tech>
09.        <tech>android.nfc.tech.NdefFormatable</tech>
10.        <tech>android.nfc.tech.MifareClassic</tech>
11.        <tech>android.nfc.tech.MifareUltralight</tech>
12.    </tech-list>
13.</resources>

另外,也可以定义多组tech-list sets。每一个tech-list set是独立的,如果任何一组tech-list set被匹配到,activity将会被启动,

该activity也可以透过getTechList()来确认侦测到的NFC tag是否与定义的tech-list sets有所匹配。它提供了 AND 与OR的定义匹配技术。

透过下列范例,说明支持NdefA与NdefB:

 

view sourceprint?
01.<resourcesxmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
02.    <tech-list>
03.        <tech>android.nfc.tech.NfcA</tech>
04.        <tech>android.nfc.tech.Ndef</tech>
05.    </tech-list>
06.</resources>
07.  
08.<resourcesxmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
09.    <tech-list>
10.        <tech>android.nfc.tech.NfcB</tech>
11.        <tech>android.nfc.tech.Ndef</tech>
12.    </tech-list>
13.</resources>

定义好了resource,可以在AppManifest.xml中指定activity透过<meta-data />定义要使用那一个resource。如下:

view sourceprint?
01.<activity>
02....
03.<intent-filter>
04.    <actionandroid:name="android.nfc.action.TECH_DISCOVERED"/>
05.</intent-filter>
06.  
07.<meta-dataandroid:name="android.nfc.action.TECH_DISCOVERED"
08.    android:resource="@xml/nfc_tech_filter"/>
09....
10.</activity>

(2-3). 注册ACTION_TAG_DISCOVERED:

 

view sourceprint?
1.<intent-filter>
2.    <actionandroid:name="android.nfc.action.TAG_DISCOVERED"/>
3.</intent-filter>

(3). 识别收到的NFC intent对象具有那些信息:
       上述介绍了应用程序要注册的intent filter后,接着要处理是当应用程序补捉到filter所要的intent对象后,该怎么取得我们要的信息。
一个NFC intent以下的信息:
‧EXTRA_TAG:(必要),一个Tag对象代表扫瞄到的tag;
‧EXTRA_NDEF_MESSAGES:(选择),代表tag中所存在的NDEF Message数组;
‧{@link android.nfc.NfcAdapter#EXTRA_ID:(选择),代表一个tag的low-level ID;
 
如果您的应用程序被一个NFC tag被扫瞄到且建立了NFC intent所启动,那该应用程序可以取得到上述三个信息,
以ACTION_NDEF_DISCOVERED为例:

view sourceprint?
01.publicvoid onResume() {
02.    super.onResume();
03.    ...
04.    if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
05.        Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
06.        if(rawMsgs != null) {
07.            msgs =new NdefMessage[rawMsgs.length];
08.            for(int i = 0; i < rawMsgs.length; i++) {
09.                msgs[i] = (NdefMessage) rawMsgs[i];
10.            }
11.        }
12.    }
13.    //process the msgs array
14.}

至于要取得Tag对象的话,可用下列方式:

Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
======

以上是介绍了Android在侦测NFC tag的机制,包括如果注册intent filter让应用程序可以取得系统所广播出来的intent,

进一步接收NDEF message intent。往下一篇,针对本篇所介绍的概念,进行对NFC tag的实作包括Reader/Writer。

0 0