【NFC】Android NFC API Reference中英文

【NFC】Android NFC API Reference中英文

SkySeraph Jan 25th 2013

Emailskyseraph00@163.com

0 Near Field Communication

Near Field Communication (NFC) is a set of   short-range wireless technologies, typically   requiring a distance of 4cm or less to initiate a connection. NFC allows you to share small payloads of   data between an NFC tag and an   Android-powered device, or between two Android-powered devices.     

近场通信(NFC)是一个短范围无线技术集合,通常需要4厘米或更短的距离才能初始化连接。NFC允许在NFC标签和Android设备之间或两个Android设备之间共享小的数据的负载。

Tags can range in complexity. Simple tags offer just   read and write semantics, sometimes with one-time-programmable areas to make   the card read-only. More complex tags offer math operations, and have   cryptographic hardware to authenticate access to a sector. The most   sophisticated tags contain operating environments, allowing complex   interactions with code executing on the tag. The data stored in the tag can   also be written in a variety of formats, but many   of the Android framework APIs are based around a NFC Forum standard called NDEF (NFC Data Exchange Format).

NFC标签具有复杂的分类。简单的NFC标签只提供读写语法,某些时候一次只能以只读的方式读取卡片的可编程区域。复杂一点的NFC标签提供了数学运算能力,而且有加密的硬件来认证对一个扇区的访问。最复杂的NFC标签包含了运算环境,允许在标签上执行复杂的交互代码。存储在标签中的数据也可以用各种格式来编写,但是大多数的Android框架API都使用基于NDEF(NFC Data Exchange Format)的标准。

1 NFC Basic

This document describes the basic NFC tasks   you perform in Android. It explains   how to send and receive NFC data in the form of NDEF messages and describes   the Android framework APIs that support these features. For more advanced topics, including a   discussion of working with non-NDEF data, see Advanced NFC.  

There are two major uses cases when working with NDEF data and Android:

    Reading   NDEF data from an NFC tag

    Beaming NDEF messages from one device to   another with Android Beam™

本文介绍在Android系通过你所能执行的基本任务。它解释了如何用NDEF消息格式来发送和接收NFC数据,并且介绍了支持这些功能的Android框架API。有关更高级的话题,包括对非NDEF格式数据的讨论,情况“高级 NFC” NDEF数据和Android一起工作的场景主要有两个:

1.   从NFC标签中读取NDEF数据;  【读数据】

2.   把NDEF消息从一个设备发送给另一个设备。【数据传递】

Reading NDEF data from an NFC tag is handled with the tag dispatch system, which analyzes   discovered NFC tags, appropriately categorizes the data, and starts an   application that is interested in the categorized data. An application that   wants to handle the scanned NFC tag can declare   an intent filter and request to handle the   data.

从NFC标签中读取NDEF数据是用标签调度系统来处理的,它会分析被发现的NFC标签,对数据进行适当的分类,并启动对该类数据感兴趣的应用程序。想要处理被扫描到NFC标签的应用程序会声明一个Intent过滤器,并请求处理数据。

 The Android Beam™ feature allows a device to   push an NDEF message onto another device by physically tapping the devices   together. This interaction provides an easier way to send data than other   wireless technologies like Bluetooth, because with NFC, no manual device   discovery or pairing is required.   The connection is automatically started when two devices come into range. Android Beam is available through a set of   NFC APIs, so any application can transmit information between devices. For   example, the Contacts, Browser, and YouTube applications use Android Beam to   share contacts, web pages, and videos with other devices.

 Android Beam™ 功能允许设备把一个NDEF消息推送到物理/硬件上相互监听的另一个设备上。这种交互提供了比其他无线技术(如蓝牙)更容易的发送数据的方法。因为NFC不需要手动的设备发现或配对要求,两个设备在接近到一定范围时会自动的连接。Android Beam通过一组NFC   API来使用,以便应用程序能够在设备之间来传输信息。例如,通信录、浏览器以及YouTube等应用程序都使用Android Beam来跟其他设备共享通信录、网页和视频。

 

 1.1 NFC标签调度系统   (The Tag Dispatch System)

 

Android-powered devices are usually looking for NFC   tags when   the screen is unlocked, unless NFC is disabled in the device's Settings menu. When an Android-powered device discovers an NFC tag, the   desired behavior is to have the most appropriate activity handle the intent   without asking the user what application to use. Because devices scan NFC tags at a very short range, it is likely   that making users manually select an activity would force them to move the   device away from the tag and break the connection. You should develop your   activity to only handle the NFC tags that your activity cares about to   prevent the Activity Chooser from appearing.

通常,除非是在设备的设置菜单中NFC被禁用,否则Android设备会在非锁屏的状态下搜索NFC。当Android设备发现NFC标签时,期望的行为是用最合适的Activity来处理该Intent,而不是询问用户使用什么应用程序。因为设备只能在很短的范围内扫描到NFC标签,强制的让用户手动的选择一个Activity,会导致设备离开NFC标签,从而中断该连接。你应该开发你自己的Activity来处理你所关心的NFC标签,从而阻止 选择器的操作。

To help you with this goal, Android provides a special   tag dispatch system that analyzes scanned NFC tags, parses them, and tries to   locate applications that are interested in the scanned data. It does this by:

      
  1. Parsing the NFC tag and figuring out the MIME type or a        URI        that identifies the data payload in the tag.
      
  1. Encapsulating the MIME type or URI and the payload into        an intent. These first two steps are described in How NFC tags are mapped to MIME types and URIs.
  2.   
  3. Starts an        activity based on the intent. This is described in How NFC Tags are Dispatched to        Applications

为了帮助你达到这个目标,Android提供了特殊的标签调度系统,来分析扫描到的NFC标签,通过解析数据,在被扫描到的数据中尝试找到感兴趣的应用程序,具体做法如下:

1.   解析NFC标签并搞清楚标签中标识数据负载的MIME类型或URI;

2.   把MIME类型或URI以及数据负载封装到一个Intent中。

3.   基于Intent来启动Activity。

 

1.1.1 怎样把NFC标签映射到MIME类型和URI  (How NFC tags are mapped to MIME types and URIs)

 

Before you begin writing your NFC applications, it is   important to understand the different types of NFC tags, how the tag dispatch   system parses NFC tags, and the special work that the tag dispatch system   does when it detects an NDEF message. NFC tags come in a wide array of   technologies and can also have data written to them in many different ways.   Android has the most support for the NDEF standard, which is defined by the NFC Forum.

开始编写NFC应用程序之前,重要的是要理解不同类型的NFC标签、标签调度系统是如何解析NFC标签的、以及在检测到NDEF消息时,标签调度系统所做的特定的工作等。NFC标签涉及到广泛的技术,并且有很多不同的方法向标签中写入数据。Android支持由NFC Forum所定义的NDEF标准。

NDEF data is encapsulated inside a message (NdefMessage) that   contains one or more records (NdefRecord). Each NDEF record must be well-formed according to the   specification of the type of record that you want to create. Android also   supports other types of tags that do not contain NDEF data, which you can   work with by using the classes in the android.nfc.tech package. To learn more about these technologies, see   the Advanced   NFC topic. Working   with these other types of tags involves writing your own protocol stack to   communicate with the tags, so we recommend using NDEF when possible for ease of development and maximum   support for Android-powered devices.

NDEF数据被封装在一个消息(NdefMessage)中,该消息中包含了一条或多条记录(NdefRecord)。每个NDEF记录必须具有良好的你想要创建的记录类型的规范的格式。Android也支持其他的不包含NDEF数据类型的标签,你能够使用android.nfc.tech包中的类来工作。要使用其他类型标签来工作,涉及到编写自己的跟该标签通信的协议栈,因此我们建议你尽可能的使用NDEF,以便减少开发难度,并且最大化的支持Android设备。

Note:To download complete NDEF specifications, go to   the NFC Forum   Specification Download site and seeCreating   common types of NDEF records for examples of   how to construct NDEF records.

 注意:要下载完整的NDEF规范,请去“NFC论坛规范下载”网址来下载。

Now that you have some background in NFC tags, the   following sections describe in more detail how Android handles NDEF formatted   tags. When an Android-powered device scans an NFC tag containing NDEF   formatted data, it parses the message and tries to figure out the data's MIME   type or identifying URI. To do this, the   system reads the first NdefRecord inside the NdefMessage to determine   how to interpret the entire NDEF message (an NDEF message can have multiple   NDEF records). In a well-formed NDEF message,   the first NdefRecordcontains the   following fields:

现在,你已经具备了一些NFC标签的背景知识,接下来要详细的介绍Android是如何处理NDEF格式的标签的。当Android设备扫描到包含NDEF格式数据的NFC标签时,它会解析该消息,并尝试搞清楚数据的MIME类型或URI标识。首先系统会读取消息(NdefMessage)中的第一条NdefRecord,来判断如何解释整个NDEF消息(一个NDEF消息能够有多条NDEF记录)。 在格式良好的NDEF消息中,第一条NdefRecord包含以下字段信息:

 3-bit TNF (Type Name Format)

Indicates how to interpret the variable   length type field. Valid values are described in described in Table   1.

Variable length type

Describes the type of the record. If using TNF_WELL_KNOWN,   use this field to specify the Record Type Definition (RTD). Valid RTD values   are described in Table   2.

Variable length ID

A unique identifier for the record. This   field is not used often, but if you need to uniquely identify a tag, you can   create an ID for it.

Variable length payload

The actual data payload that you want to read   or write. An NDEF message can contain multiple NDEF records, so don't assume   the full payload is in the first NDEF record of the NDEF message.

3-bit TNF(类型名称格式)    指示如何解释可变长度类型字段,在下表1中介绍有效值。

可变长度类型    说明记录的类型,如果使用TNF_WELL_KNOWN,那么则使用这个字段来指定记录的类型定义(RTD)。在下表2中定义了有效的RTD值。

可变长度ID    唯一标识该记录。这个字段不经常使用,但是,如果需要唯一的标识一个标记,那么就可以为该字段创建一个ID。

可变长度负载    你想读/写的实际的数据负载。一个NDEF消息能够包含多个NDEF记录,因此不要以为在NDEF消息的第一条NDEF记录中包含了所有的负载。

The tag dispatch system uses the TNF and type fields to try to   map a MIME type or URI to the NDEF message. If successful, it encapsulates   that information inside of a ACTION_NDEF_DISCOVERED   intent along with the actual payload. However, there are cases when the tag   dispatch system cannot determine the type of data based on the first NDEF   record. This happens when the NDEF data cannot be mapped to a MIME type or   URI, or when the NFC tag does not contain NDEF data to begin with. In such   cases, a Tag   object that has information about the tag's technologies and the payload are   encapsulated inside of a ACTION_TECH_DISCOVERED   intent instead.

标签调度系统使用TNF和类型字段来尝试把MIME类型或URI映射到NDEF消息中。如果成功,它会把信息跟实际的负载一起封装到ACTION_NEDF_DISCOVERED类型的Intent中。但是,会有标签调度系统不能根据第一条NDEF记录来判断数据类型的情况,这样就会有NDEF数据不能被映射到MIME类型或URI,或者是NFC标签没有包含NDEF开始数据的情况发生。在这种情况下,就会用一个标签技术信息相关的Tag对象和封装在ACTION_TECH_DISCOVERED类型Intent对象内部的负载来代替。

Table 1. describes how the tag dispatch system   maps TNF and type fields to MIME types or URIs. It also describes which TNFs   cannot be mapped to a MIME type or URI. In these cases, the tag dispatch   system falls back toACTION_TECH_DISCOVERED.

 表1. 介绍标签调度系统映射如何把TNF和类型字段映射到MIME型或URI上。同时也介绍了那种类型的TNF不能被映射到MIME类型或URI上。这种情况下,标签调度系统会退化到ACTION_TECH_DISCOVERED类型的Intent对象。

For example, if the tag dispatch system encounters a record of   type TNF_ABSOLUTE_URI,   it maps the variable length type field of that record into a URI. The tag   dispatch system encapsulates that URI in the data field of an ACTION_NDEF_DISCOVERED   intent along with other information about the tag, such as the payload. On   the other hand, if it encounters a record of type TNF_UNKNOWN,   it creates an intent that encapsulates the tag's technologies instead.

例如,如果标签调度系统遇到一个TNF_ABSOLUTE_URI类型的记录,它会把这个记录的可变长度类型字段映射到一个URI中。标签调度系统会把这个URI跟其他相关的标签的信息(如数据负载)一起封装到ACTION_NDEF_DISCOVERED的Intent对象中。在另一方面,如果遇到了TNF_UNKNOWN类型,它会创建一个封装了标签技术信息的Intent对象来代替。

 

表1.  所支持的TNF和它们的映射

 

类型名称格式(TNF)

映射

TNF_ABSOLUTE_URI

基于类型字段的URI

TNF_EMPTY

退化到ACTION_TECH_DISCOVERED类型的Intent对象

TNF_EXTERNAL_TYPE

基于类型字段中URN的URI。URN是缩短的格式(<domain_name>:<service_name)被编码到NDEF类型中。

Android会把这个URN映射成以下格式的URI:vnd.android.nfc://ext/<domain_name>:<service_name>

TNF_MIME_MEDIA

基于类型字段的MIME类型

TNF_UNCHANGED

退化到ACTION_TECH_DISCOVERED类型的Intent对象

TNF_UNKNOWN

退化到ACTION_TECH_DISCOVERED类型的Intent对象

TNF_WELL_KNOWN

依赖你在类型字段中设置的记录类型定义(RTD)的MIME类型或URI

 

表2. TNF_WELL_KNOWN所支持的RTD和它们的映射

 

记录类型定义(RTD)

映射

RTD_ALTERNATIVE_CARRIER

退化到ACTION_TECH_DISCOVERED类型的Intent对象

RTD_HANDOVER_CARRIER

退化到ACTION_TECH_DISCOVERED类型的Intent对象

RTD_HANDOVER_REQUEST

退化到ACTION_TECH_DISCOVERED类型的Intent对象

RTD_HANDOVER_SELECT

退化到ACTION_TECH_DISCOVERED类型的Intent对象

RTD_SMART_POSTER

基于负载解析的URI

RTD_TEXT

text/plain类型的MIME

RTD_URI

基于有效负载的URI

 

1.1.2 应用程序如何调度NFC标签(How NFC Tags are Dispatched to Applications)

 

 When the tag dispatch system is done   creating an intent that encapsulates the NFC tag and its identifying   information, it sends the intent to an interested application that filters   for the intent. If more than one application can handle the intent, the Activity   Chooser is presented so the user can select the Activity. The tag dispatch   system defines three intents, which are listed in order of   highest to lowest priority:

      
  1. ACTION_NDEF_DISCOVERED: This intent is used to start an Activity when a tag        that contains an NDEF payload is scanned and is of a recognized type.        This is the highest priority intent, and the tag dispatch system tries        to start an Activity with this intent before any other intent, whenever        possible.
      
  1. ACTION_TECH_DISCOVERED: If no activities register to handle the        ACTION_NDEF_DISCOVERED intent, the tag dispatch system tries to start an        application with this intent. This intent is also directly started        (without starting ACTION_NDEF_DISCOVERED first) if the tag that is        scanned contains NDEF data that cannot be mapped to a MIME type or URI,        or if the tag does not contain NDEF data but is of a known tag        technology.
      
  1. ACTION_TAG_DISCOVERED: This intent is started if no activities handle the        ACTION_NDEF_DISCOVERED or ACTION_TECH_DISCOVERED intents.

 当标签调度系统完成对NFC标签和它的标识信息封装的Intent对象的创建时,它会把该Intent对象发送给感兴趣的应用程序。如果有多个应用程序能够处理该Intent对象,就会显示Activity选择器,让用户选择Activity。标签调度系统定义了三种Intent对象,以下按照由高到低的优先级列出这三种Intent对象:

1. ACTION_NDEF_DISCOVERED: 这种Intent用于启动包含NDEF负载和已知类型的标签的Activity。这是最高优先级的Intent,并且标签调度系统在任何其他Intent之前,都会尽可能的尝试使用这种类型的Intent来启动Activity。

2. ACTION_TECH_DISCOVERED: 如果没有注册处理ACTION_NDEF_DISCOVERED类型的Intent的Activity,那么标签调度系统会尝试使用这种类型的Intent来启动应用程序。如果被扫描到的标签包含了不能被映射到MIME类型或URI的NDEF数据,或者没有包含NDEF数据,但是是已知的标签技术,那么也会直接启动这种类型的Intent对象(而不是先启动ACTION_NDEF_DISCOVERED类型的Intent)

3. ACTION_TAB_DISCOVERED:   如果没有处理ACTION_NDEF_DISCOVERED或ACTION_TECH_DISCOVERED类型Intent的Activity,就会启动这种类型的Intent。

  The basic way the tag dispatch system works is as follows:

      
  1. Try to start an Activity with the intent that was        created by the tag dispatch system when parsing the NFC tag (either        ACTION_NDEF_DISCOVERED or ACTION_TECH_DISCOVERED).
  2.   
  3. If no activities        filter for that intent, try to start an Activity with the next lowest        priority intent (either ACTION_TECH_DISCOVERED or ACTION_TAG_DISCOVERED)        until an application filters for the intent or until the tag dispatch        system tries all possible intents.
  4.   
  5. If no        applications filter for any of the intents, do nothing.

    标签调度系统的基本工作方法如下:

1.   用解析NFC标签时由标签调度系统创建的Intent对象(ACTION_NDEF_DISCOVERED或ACTION_TECH_DISCOVERED)来尝试启动Activity;

2.   如果没有对应的处理Intent的Activity,那么就会尝试使用下一个优先级的Intent(ACTION_TECH_DISCOVERED或ACTION_TAG_DISCOVERED)来启动Activity,直到有对应的应用程序来处理这个Intent,或者是直到标签调度系统尝试了所有可能的Intent。

3. 如果没有应用程序来处理任何类型的Intent,那么就不做任何事情。

Whenever possible, work with NDEF messages and the   ACTION_NDEF_DISCOVERED intent, because it is the most specific out of the   three. This intent allows you to start your application at a more appropriate   time than the other two intents, giving the user a better experience.

在可能的情况下,都会使用NDEF消息和ACTION_NDEF_DISCOVERED类型的Intent来工作,因为它是这三种Intent中最标准的。这种Intent与其他两种Intent相比,它会允许你在更加合适的时机来启动你的应用程序,从而给用户带来更好的体验。

图1. 标签调度系统 Tag Dispatch System

 

1.2 在Android的Manifest中申请NFC访问

 

Before you can access a device's NFC hardware and properly   handle NFC intents, declare these items in your AndroidManifest.xml file:

在访问设备的NFC硬件和正确的处理NFC的Intent之前,要在AndroidManifest.xml文件中进行以下声明:

 

1 The NFC <uses-permission> element   to access the NFC hardware:
    <uses-permission android:name="android.permission.NFC" />

2 The minimum SDK version that your   application can support. API level 9 only supports limited tag dispatch via ACTION_TAG_DISCOVERED, and only gives   access to NDEF messages via the EXTRA_NDEF_MESSAGES extra. No other   tag properties or I/O operations are accessible. API level 10 includes   comprehensive reader/writer support as well as foreground NDEF pushing, and   API level 14 provides an easier way to push NDEF messages to other devices   with Android Beam and extra convenience methods to create NDEF records.
    <uses-sdk android:minSdkVersion="10"/>

3 The uses-feature element so that your   application shows up in Google Play only for devices that have NFC hardware:  
    <uses-feature android:name="android.hardware.nfc"   android:required="true" />

1. 在<uses-permission>元素中声明访问NFC硬件:

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

2. 你的应用程序所支持的最小的SDK版本。API   Level 9只通过ACTION_TAG_DISCOVERED来支持有限的标签调度,并且只能通过EXTRA_NDEF_MESSAGES来访问NDEF消息。没有其他的标签属性或I/O操作可用。API   Level 10中包含了广泛的读写支持,从而更好的推动了NDEF的应用前景,并且API Leve 14用Android   Beam和额外的方便的创建NDEF记录的方法,向外提供了更容易的把NDEF消息推送给其他设备的方法。

<uses-sdkandroid:minSdkVersion="10"/>

3. 使用uses-feature元素,在Google Play中,以便你的应用程序能够只针对有NFC硬件的设备来显示。

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

If your application uses NFC functionality, but that   functionality is not crucial to your application, you can omit the   uses-feature element and check for NFC avalailbility at runtime by checking   to see if getDefaultAdapter()is   null.

如果你的应用程序使用了NFC功能,但是相关的功能又不是你的应用程序的关键功能,你可以忽略uses-feature元素,并且要在运行时通过调用getDefaultAdapter()方法来检查NFC是否有效。

1.3 过滤NFC的Intent (Filtering for NFC Intents)

To start your application when an NFC tag that you want   to handle is scanned, your application can   filter for one, two, or all three of the NFC intents in the Android manifest.

      
  1. However, you usually want to filter for        the ACTION_NDEF_DISCOVERED intent for the most control of when your application        starts.
  2.   
  3. The        ACTION_TECH_DISCOVERED intent is a fallback for        ACTION_NDEF_DISCOVERED when no applications filter for        ACTION_NDEF_DISCOVERED or for when the payload is not NDEF.
  4.   
  5. Filtering for ACTION_TAG_DISCOVERED is usually too general of a category to filter on. Many        applications will filter for ACTION_NDEF_DISCOVERED or        ACTION_TECH_DISCOVERED before ACTION_TAG_DISCOVERED, so your application        has a low probability of starting.  ACTION_TAG_DISCOVERED is only        available as a last resort for applications to filter for in the cases        where no other applications are installed to handle the        ACTION_NDEF_DISCOVERED or ACTION_TECH_DISCOVEREDintent.

 要在你想要处理被扫描到的NFC标签时启动你的应用程序,可以在你的应用程序的Android清单中针对一种、两种或全部三种类型的NFC的Intent来过滤。

      
  1. 但是,通常想要在应用程序启动时控制最常用的ACTION_NDEF_DISCOVERED类型的Intent。
  2.   
  3. 在没有过滤ACTION_NDEF_DISCOVERED类型的Intent的应用程序,或数据负载不是NDEF时,才会从ACTION_NDEF_DISCOVERED类型的Intent回退到ACTION_TECH_DISCOVERED类型的Intent。
  4.   
  5. 通常ACTION_TAB_DISCOVERED是最一般化的过滤分类。很多应用程序都会在过滤ACTION_TAG_DISCOVERED之前,过滤ACTION_NDEF_DISCOVERED或ACTION_TECH_DISCOVERED,这样就会降低你的应用程序被启动的可能性。ACTION_TAG_DISCOVERED只是在没有应用程序处理ACTION_NDEF_DISCOVERED或ACTION_TECH_DISCOVERED类型的Intent的情况下,才使用的最后手段。

Because NFC tag deployments vary and are many times not under your control, this is not always possible, which is why you can   fallback to the other two intents when necessary. When you have control over   the types of tags and data written, it is   recommended that you use NDEF to format your tags. The following sections describe how to filter for   each type of intent.

因为NFC标签的多样性,并且很多时候不在你的控制之下,因此在必要的时候你要回退到其他两种类型的Intent。在你能够控制标签的类型和写入的数据时,我们建议你使用NDEF格式。下文将介绍如何过滤每种类型的Intent对象。

1.3.1  ACTION_NDEF_DISCOVERED

To filter for ACTION_NDEF_DISCOVERED intents, declare the   intent filter along with the type of data that you want to filter for.

The following example filters for ACTION_NDEF_DISCOVERED   intents with a MIME type of text/plain:

<intent-filter>

<action android:name="android.nfc.action.NDEF_DISCOVERED"/>

<category android:name="android.intent.category.DEFAULT"/>

<data android:mimeType="text/plain" />

</intent-filter>

 

The following example filters for a URI in the form of http://developer.android.com/index.html.

<intent-filter>

<action android:name="android.nfc.action.NDEF_DISCOVERED"/>

<category android:name="android.intent.category.DEFAULT"/>

<data android:scheme="http"

           android:host="developer.android.com"

           android:pathPrefix="/index.html"   />

</intent-filter>

要过滤ACTION_NDEF_DISCOVERED类型的Intent,就要在清单中跟你想要过滤的数据一起来声明该类型的Intent过滤器。

以下是过滤text/plain类型的MIME的ACTION_NDEF_DISCOVERED类型过滤器的声明:

<intent-filter>

<action android:name="android.nfc.action.NDEF_DISCOVERED"/>

<category android:name="android.intent.category.DEFAULT"/>

<data android:mimeType="text/plain" />

</intent-filter>

 

以下示例使用http://developer.android.com/index.html格式的URI来过滤

<intent-filter>

<action android:name="android.nfc.action.NDEF_DISCOVERED"/>

<category android:name="android.intent.category.DEFAULT"/>

<data android:scheme="http"

           android:host="developer.android.com"

           android:pathPrefix="/index.html"   />

</intent-filter>

1.3.2 ACTION_TECH_DISCOVERED

If your activity filters for the ACTION_TECH_DISCOVERED   intent, you must create an XML resource file that specifies the technologies   that your activity supports within a tech-list set. Your activity is   considered a match if a tech-list set is a subset of the technologies that   are supported by the tag, which you can obtain by calling getTechList().

如果你的Activity要过滤ACTION_TECH_DISCOVERED类型的Intent,你必须创建一个XML资源文件,该文件在tech-list集合中指定你的Activity所支持的技术。如果tech-list集合是标签所支持的技术的一个子集,那么你的Activity被认为是匹配的。通过调用getTechList()方法来获得标签所支持的技术集合。

For example, if the tag that is scanned supports   MifareClassic, NdefFormatable, and NfcA, your tech-list set must specify all   three, two, or one of the technologies (and nothing else) in order for your   activity to be matched.

例如,如果扫描到的标签支持MifareClassic、NdefFormatable和NfcA,那么为了跟它们匹配,tech-list集合就必须指定所有这三种技术,或者指定其中的两种或一种。

The following sample defines all of the technologies.   You can remove the ones that you do not need. Save this file (you can name it   anything you wish) in the   <project-root>/res/xml folder.

以下示例定义了所有的相关的技术。你可以根据需要删除其中一些设置。然后把这个文件保存到<project-root>/res/xml文件夹中(你能够把命名为任何你希望的名字):

 

View Code
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">



<tech-list>



<tech>android.nfc.tech.IsoDep</tech>



<tech>android.nfc.tech.NfcA</tech>



<tech>android.nfc.tech.NfcB</tech>



<tech>android.nfc.tech.NfcF</tech>



<tech>android.nfc.tech.NfcV</tech>



<tech>android.nfc.tech.Ndef</tech>



<tech>android.nfc.tech.NdefFormatable</tech>



<tech>android.nfc.tech.MifareClassic</tech>



<tech>android.nfc.tech.MifareUltralight</tech>



</tech-list>



</resources>

 

You can also specify multiple tech-list sets. Each of the tech-list sets is considered   independently, and your activity is considered a match if any single   tech-list set is a subset of the technologies that are returned by getTechList(). This provides AND and OR semantics for matching   technologies.

The following example matches tags that can support the NfcA   and Ndef technologies or can support the NfcB and Ndef technologies:

你也能够指定多个tech-list集合,每个tech-list集合被认为是独立的,并且如果任何一个tech-list集合是由getTechList()返回的技术的子集,那么你的Activity就被认为是匹配的。

下列示例能够跟支持NfcA和Ndef技术NFC标签或者跟支持NfcB和Ndef技术的标签相匹配:

View Code
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">



<tech-list>



<tech>android.nfc.tech.NfcA</tech>



<tech>android.nfc.tech.Ndef</tech>



</tech-list>



</resources>



<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">



<tech-list>



<tech>android.nfc.tech.NfcB</tech>



<tech>android.nfc.tech.Ndef</tech>



</tech-list>



</resources>

 

In your AndroidManifest.xml file, specify the resource file   that you just created in the <meta-data> element inside the   <activity> element like in the following example:

在你的AndroidManifest.xml文件中,要像向下列示例那样,在<activity>元素内的<meta-data>元素中指定你创建的资源文件:

View Code
<activity>



...



<intent-filter>



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



</intent-filter>



<meta-data android:name="android.nfc.action.TECH_DISCOVERED"



android:resource="@xml/nfc_tech_filter" />



...



</activity>

1.3.3 ACTION_TAG_DISCOVERED

 

To filter for ACTION_TAG_DISCOVERED   use the following intent filter:

使用下列Intent过滤器来过滤ACTION_TAG_DISCOVERED类型的Intent:

 

View Code
<intent-filter>



<action android:name="android.nfc.action.TAG_DISCOVERED"/>



</intent-filter>

1.3.4 从Intent中获取信息  (Obtaining information from intents)

If an activity starts because of an NFC intent, you can obtain   information about the scanned NFC tag from the intent. Intents can contain   the following extras depending on the tag that was scanned:

如果因为NFC的Intent而启动一个Activity,那么你就能够从Intent中获取被扫描到的NFC标签的相关信息。根据被扫描到的标签,Intent对象能够以下额外的信息:

EXTRA_TAG (required): A Tag object representing the scanned tag.

EXTRA_NDEF_MESSAGES (optional): An array of NDEF messages   parsed from the tag. This extra is mandatory on intents.

{@link android.nfc.NfcAdapter#EXTRA_ID

(optional): The low-level ID of the tag.

1. EXTRA_TAG(必须的):它是一个代表了被扫描到的标签的Tag对象;

2.   EXTRA_NDEF_MESSAGES(可选):它是一个解析来自标签中的NDEF消息的数组。这个附加信息是强制在Intent对象上的;

3. {@link android.nfc.NfcAdapter#EXTRA_ID(可选):标签的低级ID。

To obtain these extras, check to see if your activity was   launched with one of the NFC intents to ensure that a tag was scanned, and   then obtain the extras out of the intent. The following example checks for   the ACTION_NDEF_DISCOVEREDintent   and gets the NDEF messages from an intent extra.

要获取这些附加信息,就要确保你的Activity是被扫描到的NFC的Intent对象启动的,然后才能获得Intent之外的附加信息。

下例检查ACTION_NDEF_DISCOVERED类型的Intent,并从Intent对象的附加信息中获取NDEF消息。

View Code
public void onResume() {



super.onResume();



...



if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {



    Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);



    if (rawMsgs != null) {



        msgs = new NdefMessage[rawMsgs.length];



        for (int i = 0; i < rawMsgs.length; i++) {



            msgs[i] = (NdefMessage) rawMsgs[i];



        }



    }



}



//process the msgs array



}

 

Alternatively, you can obtain a Tag   object from the intent, which will contain the payload and allow you to   enumerate the tag's technologies:

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

此外,你还能够从Intent对象中获得一个Tag对象,该对象包含了数据负载,并允许你列举标签的技术:

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

1.4 创建通用的NDEF记录类型 (Creating Common Types of NDEF Records)

 

This section describes how to create common types of NDEF   records to help you when writing to NFC tags or sending data with Android   Beam. Starting with Android 4.0 (API level 14), thecreateUri()   method is available to help you create URI records automatically. Starting in   Android 4.1 (API level 16), createExternal()and   createMime()   are available to help you create MIME and external type NDEF records. Use   these helper methods whenever possible to avoid mistakes when manually   creating NDEF records.

This section also describes how to create the corresponding   intent filter for the record. All of these NDEF record examples should be in   the first NDEF record of the NDEF message that you are writing to a tag or   beaming.

本节介绍如何创建通用的NDEF记录类型,以便帮助你向NFC标签写入或用Android Beam发送数据。

从Android4.0(API Level14)开始,可以用createUri()方法来帮助你自动的创建URI记录。

从Android4.1(API Level   16)开始,可以用createExternal()和createMime()方法来帮助你创建MIME和外部类型的NDEF记录。

使用这些辅助方法会尽可能的避免手动创建NDEF记录的错误。

本节还要介绍如何创建NDEF记录对应的Intent过滤器。所有的这些写入或发送到NFC标签的NDEF记录例子都应该是NDEF消息的第一条记录。

1.4.1 TNF_ABSOLUTE_URI

 

Note: We recommend that you use the RTD_URI   type instead of TNF_ABSOLUTE_URI,   because it is more efficient.

注意:我们推荐你使用RTD_URI类型,而不是TNF_ABSOLUTE_URI, 因为它更高效。

You can create a TNF_ABSOLUTE_URI   NDEF record in the following way:

用下列方法创建一个TNF_ABSOLUTE_URI类型的NDEF记录:

 

NdefRecord uriRecord = new NdefRecord( NdefRecord.TNF_ABSOLUTE_URI ,"http://developer.android.com/index.html".getBytes(Charset.forName("US-ASCII")),new byte[0], new byte[0]);

 

The intent filter for the previous NDEF record would look like   this:

对应的Intent过滤器如下:

 

<intent-filter>



<action android:name="android.nfc.action.NDEF_DISCOVERED" />



<category android:name="android.intent.category.DEFAULT" />



<data android:scheme="http"



           android:host="developer.android.com"



           android:pathPrefix="/index.html" />



</intent-filter>



 

1.4.2 TNF_MIME_MEDIA

 

You can create a TNF_MIME_MEDIA NDEF record in the   following ways.

Using the createMime()   method:

使用下列方法创建TNF_MIME_MEDIA类型的NDEF记录。

使用createMime()方法:

 

NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam","Beam me up, Android".getBytes(Charset.forName("US-ASCII")));

 

Creating the NdefRecord   manually:

手动的创建NdefRecord:

 

NdefRecord mimeRecord = new NdefRecord(NdefRecord.TNF_MIME_MEDIA ,"application/vnd.com.example.android.beam".getBytes(Charset.forName("US-ASCII")),

 

new byte[0], "Beam me up, Android!".getBytes(Charset.forName("US-ASCII")));

 

The intent filter for the previous NDEF records would look   like this:

对应的Intent过滤器如下:

View Code
<intent-filter>



<action android:name="android.nfc.action.NDEF_DISCOVERED" />



<category android:name="android.intent.category.DEFAULT" />



<data android:mimeType="application/vnd.com.example.android.beam" />



</intent-filter>

1.4.3 TNF_WELL_KNOWN和RTD_TEXT

 

You can create a TNF_WELL_KNOWN   NDEF record in the following way:

public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {

    byte[] langBytes =   locale.getLanguage().getBytes(Charset.forName("US-ASCII"));

    Charset   utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");

    byte[] textBytes =   payload.getBytes(utfEncoding);

    int utfBit = encodeInUtf8 ? 0 : (1 << 7);

    char status = (char) (utfBit + langBytes.length);

    byte[] data = new byte[1 + langBytes.length + textBytes.length];

    data[0] = (byte)   status;

    System.arraycopy(langBytes,   0, data, 1,   langBytes.length);

    System.arraycopy(textBytes,   0, data, 1 + langBytes.length,   textBytes.length);

    NdefRecord record   = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,

    NdefRecord.RTD_TEXT,   new byte[0], data);

    return record;

}

用下列方法创建TNF_WELL_KNOWN类型的NDEF记录:

public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) {

    byte[] langBytes =   locale.getLanguage().getBytes(Charset.forName("US-ASCII"));

    Charset   utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16");

    byte[] textBytes =   payload.getBytes(utfEncoding);

    int utfBit = encodeInUtf8 ? 0 : (1 << 7);

    char status = (char) (utfBit + langBytes.length);

    byte[] data = new byte[1 + langBytes.length + textBytes.length];

    data[0] = (byte)   status;

    System.arraycopy(langBytes,   0, data, 1,   langBytes.length);

    System.arraycopy(textBytes,   0, data, 1 + langBytes.length,   textBytes.length);

    NdefRecord record   = new NdefRecord(NdefRecord.TNF_WELL_KNOWN,

    NdefRecord.RTD_TEXT,   new byte[0], data);

    return record;

}

the intent filter would look like this:

<intent-filter>

<action android:name="android.nfc.action.NDEF_DISCOVERED" />

<category android:name="android.intent.category.DEFAULT" />

<data android:mimeType="text/plain" />

</intent-filter>

对应的Intent过滤器如下:

<intent-filter>

<action android:name="android.nfc.action.NDEF_DISCOVERED" />

<category android:name="android.intent.category.DEFAULT" />

<data android:mimeType="text/plain" />

</intent-filter>

1.4.4 TNF_WELL_KNOW和RTD_URI

You can create a TNF_WELL_KNOWN NDEF record in the following ways.

Using the createUri(String) method:

NdefRecord   rtdUriRecord1=NdefRecord.createUri("http://example.com");

用下列方法创建TNF_WELL_KNOWN类型的NDEF记录。

使用createUri(String)方法:

NdefRecord   rtdUriRecord1=NdefRecord.createUri("http://example.com");

Using   the createUri(Uri)   method:

Uri uri = new Uri("http://example.com");

NdefRecord   rtdUriRecord2 = NdefRecord.createUri(uri);

使用createUri(Uri)方法:

Uri uri = new Uri("http://example.com");

NdefRecord   rtdUriRecord2 = NdefRecord.createUri(uri);

Creating   the NdefRecord   manually:

byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII"));

byte[] payload = new byte[uriField.length + 1]; //add 1 for the URI Prefix

byte payload[0]   = 0x01; //prefixes http://www. to the URI

System.arraycopy(uriField,   0,   payload, 1, uriField.length); //appends   URI to payload

NdefRecord   rtdUriRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);

手动的创建NdefRecord:

byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII"));

byte[] payload = new byte[uriField.length + 1]; //add 1 for the URI Prefix

byte payload[0]   = 0x01; //prefixes http://www. to the URI

System.arraycopy(uriField,   0,   payload, 1, uriField.length); //appends   URI to payload

NdefRecord   rtdUriRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);

The   intent filter for the previous NDEF records would look like this:

<intent-filter>

<action android:name="android.nfc.action.NDEF_DISCOVERED" />

<category android:name="android.intent.category.DEFAULT" />

<data android:scheme="http"

android:host="example.com"

android:pathPrefix=""   />

</intent-filter>

对应的Intent过滤器如下:

<intent-filter>

<action android:name="android.nfc.action.NDEF_DISCOVERED" />

<category android:name="android.intent.category.DEFAULT" />

<data android:scheme="http"

android:host="example.com"

android:pathPrefix=""   />

</intent-filter>

1.4.5 TNF_EXTERNAL_TYPE

You can create a TNF_EXTERNAL_TYPE NDEF record in the   following ways:

Using the createExternal()   method:

使用下列方法创建TNF_EXTERNAL_TYPE类型的记录。

使用createExternal()方法:

 

byte[] payload; //assign to your data



String domain = "com.example"; //usually your app's package name



String type = "externalType";



NdefRecord extRecord = NdefRecord.createExternal(domain, type, payload);

 

Creating the NdefRecord   manually:

手动的创建NdefRecord:

 

byte[] payload;



...



NdefRecord extRecord = new NdefRecord(



NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType", new byte[0], payload);

 

 

The intent filter for the previous NDEF records would look   like this:

对应的Intent过滤器如下:

<intent-filter>



<action android:name="android.nfc.action.NDEF_DISCOVERED" />



<category android:name="android.intent.category.DEFAULT" />



<data android:scheme="vnd.android.nfc"



android:host="ext"



android:pathPrefix="/com.example:externalType"/>



</intent-filter>

 

Use TNF_EXTERNAL_TYPE for more generic NFC tag deployments to   better support both Android-powered and non-Android-powered devices.

使用更加一般化的TNF_EXTERNAL_TYPE类型NFC部署,以便更好的支持Android设备和非Android设备。

Note: URNs for TNF_EXTERNAL_TYPE   have a canonical format of:urn:nfc:ext:example.com:externalType, however the   NFC Forum RTD specification declares that the urn:nfc:ext: portion of the URN   must be ommitted from the NDEF record. So all you need to provide is the   domain (example.com in the example) and type (externalType in the example)   separated by a colon. When dispatching TNF_EXTERNAL_TYPE, Android converts   the urn:nfc:ext:example.com:externalType URN to   avnd.android.nfc://ext/example.com:externalType URI, which is what the intent   filter in the example declares.

注意:TNF_EXTERNAL_TYPE类型的URN包含以下格式:

urn:nfc:ext:example.com.externalType,但是,NFC论坛的RTD规范声明,URN的urn:nfc:ext:部分在NDEF记录中必须忽略。因此你需要提供的所有信息是用“:”号把域名(示例中的example.com)和类型(示例中的externalType)分离开。在调度TNF_EXTERNAL_TYPE类型的记录时,Android会把urn:nfc:ext:example.com:externalType的URN转换成vnd.android.nfc://ext/example.com:externalType的URI,它是在示例中声明的Intent过滤器。

 

 1.5 Android应用程序记录(Android Application Record---AAR)

 

Introduced in Android 4.0 (API level 14), an Android   Application Record (AAR) provides a stronger certainty that your application   is started when an NFC tag is scanned. An AAR has the package name of an   application embedded inside an NDEF record. You can add an AAR to any NDEF   record of your NDEF message, because Android searches the entire NDEF message   for AARs. If it finds an AAR, it starts the application based on the package   name inside the AAR. If the application is not present on the device, Google   Play is launched to download the application.

在Android4.0(API Level   14)中引入的Android应用程序记录(AAR),提供了较强的在扫描到NFC标签时,启动应用程序的确定性。AAR有嵌入到NDEF记录内部的应用程序的包名。你能够把一个AAR添加到你的NDEF消息的任何记录中,因为Android会针对AAR来搜索整个NDEF消息。如果它找到一个AAR,它就会基于AAR内部的包名来启动应用程序。如果该应用程序不在当前的设备上,会启动Google   Play来下载对应的应用程序。

AARs are useful if you want to prevent other applications from   filtering for the same intent and potentially handling specific tags that you   have deployed. AARs are only supported at the application level, because of   the package name constraint, and not at the Activity level as with intent   filtering. If you want to handle an intent at the Activity level, use   intent filters.

If a tag contains an AAR, the tag dispatch system dispatches   in the following manner:

如果你想要防止其他的应用对相同的Intent的过滤并潜在的处理你部署的特定的NFC标签,那么AAR是有用的。AAR仅在应用程序级被支持,因为包名的约束,并不能在Activity级别来过滤Intent。如果你想要在Activity级处理Intent,请使用Intent过滤器。

如果NFC标签中包含了AAR,则NFC标签调度系统会按照下列方式来调度:

      
         
    1. Try to start an Activity using an intent filter as         normal. If the Activity that matches the intent also matches the AAR,         start the Activity.
    2.    
    3. If the Activity         that filters for the intent does not match the AAR, if multiple         Activities can handle the intent, or if no Activity handles the intent,         start the application specified by the AAR.
    4.    
    5. If no         application can start with the AAR, go to Google Play to download the         application based on the AAR.
    6.   

1. 通常,尝试使用Intent过滤器来启动一个Activity。如果跟该Intent匹配的Activity也跟AAR匹配,那么就启动该Activity。

2. 如果跟Intent队形的Activity跟AAR不匹配,或者是有多个Activity能够处理该Intent,或者是没有能够处理该Intent的Activity存在,那么就启动由AAR指定的应用程序。

3. 如果没有跟该AAR对应的应用程序,那么就会启动Google   Play来小组基于该AAR的应用程序。

Note: You can override AARs and the intent dispatch system   with the foreground   dispatch system, which allows a foreground activity to have priority when   an NFC tag is discovered. With this method, the activity must be in the   foreground to override AARs and the intent dispatch system.

注意:你能够用前台调度系统来重写AAR和Intent调度系统,在NFC标签被发现时。它允许优先使用前台的Activity。用这种方法,Activity必须是在前台来重写AAR和Intent调度系统。

If you still want to filter for scanned tags that do not   contain an AAR, you can declare intent filters as normal. This is useful if   your application is interested in other tags that do not contain an AAR. For   example, maybe you want to guarantee that your application handles   proprietary tags that you deploy as well as general tags deployed by third   parties. Keep in mind that AARs are specific to Android 4.0 devices or later,   so when deploying tags, you most likely want to use a combination of AARs and   MIME types/URIs to support the widest range of devices. In addition, when you   deploy NFC tags, think about how you want to write your NFC tags to enable   support for the most devices (Android-powered and other devices). You can do   this by defining a relatively unique MIME type or URI to make it easier for   applications to distinguish.

如果你依然想要过滤扫描到的没有包含AAR的NFC标签,通常,你能够声明Intent过滤器。如果你的应用程序对不包含AAR的其他NFC标签感兴趣,这种做法是有用的。例如,你可能想要保证你的应用程序处理你部署的专用NFC标签,以及由第三方部署的普通的NFC标签。要记住AAR是在Android4.0以后才指定的,因此部署NFC标签时,你很可能希望使用能够广泛支持AAR和MIME类型/URI的是设备。另外,在你部署NFC标签时,还要想如何编写你的NFC标签,以便让大多数设备(Android设备和其他设备)支持。同过定义相对唯一的MIME类型或URI,让应用程序更容易的区分,就可以做到这一点。

Android provides a simple API to create an AAR,createApplicationRecord().   All you need to do is embed the AAR anywhere in your NdefMessage.   You do not want to use the first record of your NdefMessage,   unless the AAR is the only record in the NdefMessage.   This is because the Android system checks the first record of an NdefMessage   to determine the MIME type or URI of the tag, which is used to create an   intent for applications to filter. The following code shows you how to create   an AAR:

Android提供了简单的创建AAR的API:createApplicationRecord()。你需要做的所有工作就是把AAR嵌入到你的NdefMessage中。除非AAR是NdefMessage中的唯一记录,否则不要把使用NdefMessage的第一条记录。这是因为,Android系统会检查NdefMessage的第一条记录来判断NFC标签的MIME类型或URI,这些信息被用于创建对应应用程序的Intent对象。以下代码演示了如何创建一个AAR:

NdefMessage msg = new NdefMessage(



new NdefRecord[] {



...,



NdefRecord.createApplicationRecord("com.example.android.beam")}



 



 

1.6 把NDEF消息发射到其他设备上

 

Android Beam allows simple peer-to-peer data exchange between   two Android-powered devices. The application that wants to beam data to   another device must be in the foreground and the device receiving the data   must not be locked. When the beaming device comes in close enough contact   with a receiving device, the beaming device displays the "Touch to   Beam" UI. The user can then choose whether or not to beam the message to   the receiving device.

Android Beam允许在两个Android设备之间进行简单的对等数据交换,想要把数据发送给另一个设备的应用程序必须是在前台,并且接收数据的设备必须不被锁定。当发射设备跟接收设备的距离足够近的时候,发射设备会显示“Touch to Beam(触摸发射)”的UI。然后,用户能够选择是否把消息发射给接收设备。

Note: Foreground NDEF pushing was available at API level   10, which provides similar functionality to Android Beam. These APIs have   since been deprecated, but are available to support older devices. SeeenableForegroundNdefPush() for   more information.

注意:在API   Level 10中可以利用前台的NDEF推送,它提供了与Android   Beam类似的功能。这些API已经过时了,但是在一些老旧设备上还有效。更多的信息请看enableForegroundNdefPush()

You can enable Android Beam for your application by calling   one of the two methods:

      
  1. setNdefPushMessage(): Accepts an NdefMessage to set as the message to beam. Automatically        beams the message when two devices are in close enough proximity.
  2.   
  3. setNdefPushMessageCallback(): Accepts a        callback that contains a createNdefMessage() which is        called when a device is in range to beam data to. The callback lets you        create the NDEF message only when necessary.

通过调用下列两个方法中的任意一个,就能够为你的应用程序启用Android Beam:

1. setNdefPushMessage():这个方法把接收到的NdefMessage对象作为一个消息设置给Beam。当两个设备足够近的时候,就会自动的发送消息。

2. setNdefPushMessageCallback():接收包含createNdefMessage()方法的回调,当设备在发射数据的范围内时,这个回调方法会被调用。回调会让你只在需要的时候创建NDEF消息。

An activity can only push one NDEF message at a time, so setNdefPushMessageCallback() takes   precedence over setNdefPushMessage() if   both are set. To use Android Beam, the following general guidelines must be   met:

      
  1. The activity that is beaming the data must be in the        foreground. Both devices must have their screens unlocked.
  2.   
  3. You must        encapsulate the data that you are beaming in an NdefMessage object.
  4.   
  5. The NFC device        that is receiving the beamed data must support        the com.android.npp NDEF push protocol or NFC Forum's SNEP        (Simple NDEF Exchange Protocol). The com.android.npp protocol        is required for devices on API level 9 (Android 2.3) to API level 13        (Android 3.2). com.android.npp and SNEP are both required on        API level 14 (Android 4.0) and later.

一个Activity一次只能推送一条NDEF消息,因此如果同时使用了这两种方法,那么setNdefPushMessageCallback()方法的优先级要高于setNdefPushMessage()方法。要使用Android Beam,通常必须满足以下条件:

1. 发射数据的Activity必须是在前台。两个设备的屏幕都必须没有被锁定;

2. 必须发要发射的数据封装到一个NdefMessage对象中;

3. 接收发射数据的NFC设备必须支持com.android.npp   NDEF推送协议或是NFC组织的SNEP协议(简单的NDEF交换协议)。在API Level9(Android2.3)到API Level   13(Android3.2)的设备上需要com.android.npp协议。在API Level   14(Android4.0)和以后的设备上,com.android.npp和SNEP都需要。

Note: If your activity enables Android Beam and is in the   foreground, the standard intent dispatch system is disabled. However, if your   activity also enables foreground   dispatching, then it can still scan tags that match the intent filters   set in the foreground dispatching.

注意:如果在前台的Activity启用了Android Beam,那么标准的Intent调度系统就会被禁用。但是,如果该Activity还启用了前台调度,那么在前台调度系统中,它依然能够扫描到跟Intent过滤器匹配的NFC标签。

To enable Android Beam:

      
  1. Create an NdefMessage that contains the NdefRecords that you want to push onto the other device.
  2.   
  3. Call setNdefPushMessage() with        a NdefMessage or        call setNdefPushMessageCallback passing in        aNfcAdapter.CreateNdefMessageCallback object in        the onCreate() method of your activity. These methods require        at least one activity that you want to enable with Android Beam, along        with an optional list of other activities to activate.

In general, you normally use setNdefPushMessage() if   your Activity only needs to push the same NDEF message at all times, when two   devices are in range to communicate. You usesetNdefPushMessageCallback when   your application cares about the current context of the application and wants   to push an NDEF message depending on what the user is doing in your   application.

启用Android Beam:

1. 创建一个准备推送到另一个设备上的包含NdefRecord的NdefMessage对象。

2. 调用带有NdefMessage类型参数的setNdefPushMessage()方法,或者是在Activity的onCreate()方法中调用setNdefPushMessageCallback方法来传递实现NfcAdapter.CreateNdefMessageCallback接口的对象。这两个方法都至少需要一个准备要启用Android   Beam的Activity,以及一个可选的其他的活跃的Activity列表。

通常,如果你的Activity在任何时候都值推送相同的NDEF消息,那么当两个设备在通信范围内的时候,使用setNdefPushMessage()就可以了。当你的应用程序要关注应用程序的当前内容,并想要根据用户在你的应用程序中的行为来推送NDEF消息时,就要使用setNdefPushMessageCallback方法。

The following sample shows how a simple activity calls NfcAdapter.CreateNdefMessageCallback in   theonCreate() method of an activity (see AndroidBeamDemo for   the complete sample). This example also has methods to help you create a MIME   record:

下列示例代码演示了如何在activity的onCreate()方法中调用NfcAdapter.CreateNdefMessageCallback方法(完整的示例请看AndroidBeamDemo)。这个示例中还有帮助创建MIME记录的方法:

 

package com.example.android.beam;

import android.app.Activity;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.os.Parcelable;
import android.widget.TextView;
import android.widget.Toast;
import java.nio.charset.Charset;

publicclassBeamextendsActivityimplementsCreateNdefMessageCallback{
NfcAdapter mNfcAdapter;
TextView textView;

@Override
publicvoid onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
 setContentView(R.layout.main);
TextView textView =(TextView) findViewById(R.id.textView);
// Check for available NFC Adapter
 mNfcAdapter =NfcAdapter.getDefaultAdapter(this);
if(mNfcAdapter ==null){
Toast.makeText(this,"NFC is not available",Toast.LENGTH_LONG).show();
 finish();
return;
}
// Register callback
 mNfcAdapter.setNdefPushMessageCallback(this,this);
}

@Override
publicNdefMessage createNdefMessage(NfcEventevent){
String text =("Beam me up, Android!\n\n"+
"Beam Time: "+System.currentTimeMillis());
NdefMessage msg =newNdefMessage(
newNdefRecord[]{ createMime(
"application/vnd.com.example.android.beam", text.getBytes())
/**
 * The Android Application Record (AAR) is commented out. When a device
 * receives a push with an AAR in it, the application specified in the AAR
 * is guaranteed to run. The AAR overrides the tag dispatch system.
 * You can add it back in to guarantee that this
 * activity starts when receiving a beamed message. For now, this code
 * uses the tag dispatch system.
 */
//,NdefRecord.createApplicationRecord("com.example.android.beam")
});
return msg;
}

@Override
publicvoid onResume(){
super.onResume();
// Check to see that the Activity started due to an Android Beam
if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())){
 processIntent(getIntent());
}
}

@Override
publicvoid onNewIntent(Intent intent){
// onResume gets called after this to handle the intent
 setIntent(intent);
}

/**
 * Parses the NDEF Message from the intent and prints to the TextView
 */
void processIntent(Intent intent){
 textView =(TextView) findViewById(R.id.textView);
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
// only one message sent during the beam
NdefMessage msg =(NdefMessage) rawMsgs[0];
// record 0 contains the MIME type, record 1 is the AAR, if present
 textView.setText(newString(msg.getRecords()[0].getPayload()));
}
}

 

 

Note that this code comments out an AAR, which you can remove.   If you enable the AAR, the application specified in the AAR always receives   the Android Beam message. If the application is not present, Google Play is   started to download the application. Therefore, the following intent filter   is not technically necessary for Android 4.0 devices or later if the AAR is   used:

注意:上例代码把AAR给注释掉了,你可以删除它。如果你启用了AAR,那么该应用程序就会始终接收在AAR中指定的Android   Beam消息。如果该应用程序不存在,Google   Play就会启动下载程序。因此,如果使用AAR,对于Android4.0以后的设备,下列的Intent过滤器,在技术上不是必须的:

<intent-filter>
  <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
  <category android:name="android.intent.category.DEFAULT"/>
  <data android:mimeType="application/vnd.com.example.android.beam"/>
</intent-filter>

With this intent filter, the com.example.android.beam   application now can be started when it scans an NFC tag or receives an   Android Beam with an AAR of type com.example.android.beam, or when an NDEF   formatted message contains a MIME record of type application/vnd.com.example.android.beam.

有了这个Intent过滤器,com.example.android.beam应用就能够在以下情况下被启动:

1. 扫描到NFC标签;

2. 接收到com.example.android.beam类型的AAR或NDEF消息中包含一条application/vnd.com.example.android.beam类型的MIME记录的Android   beam的时候。

Even though AARs guarantee an application is started or   downloaded, intent filters are recommended, because they let you start an   Activity of your choice in your application instead of always starting the   main Activity within the package specified by an AAR. AARs do not have   Activity level granularity. Also, because some Android-powered devices do not   support AARs, you should also embed identifying information in the first NDEF   record of your NDEF messages and filter for that as well, just in case. See Creating   Common Types of NDEF records for more information on how to create   records.

即使通过AAR能够保证了一个应用程序被启动或下载,但是还是推荐使用Intent过滤器,因为它会让你选择启动应用程序中Activity,而不是总启动AAR中指定的应用程序包的主Activity。AAR没有Activity级别的粒度。而且还有一些android设备不支持AAR,你还应该在NDEF消息的第一条NDEF记录中嵌入标识信息,以及对应的过滤器。

 

2  Advanced  NFC

This document describes advanced NFC topics, such as working   with various tag technologies, writing to NFC tags, and foreground   dispatching, which allows an application in the foreground to handle intents   even when other applications filter for the same ones.

本文介绍一些高级的NFC专题,如多样的NFC标签技术、编写NFC标签、以及前台调度,前台调度允许在前台的应用程序优先调度Intent事件,即使还有其他的过滤同样的Intent事件的应用程序存在。

2.1 Android所支持的NFC标签技术

When working with NFC tags and Android-powered devices, the   main format you use to read and write data on tags is NDEF. When a device   scans a tag with NDEF data, Android provides support in parsing the message   and delivering it in an NdefMessage   when possible. There are cases, however, when you scan a tag that does not   contain NDEF data or when the NDEF data could not be mapped to a MIME type or   URI. In these cases, you need to open communication directly with the tag and   read and write to it with your own protocol (in raw bytes). Android provides   generic support for these use cases with theandroid.nfc.tech   package, which is described in Table   1. You can use the getTechList()   method to determine the technologies supported by the tag and create the   corresponding TagTechnologyobject   with one of classes provided by android.nfc.tech

在使用NFC标签和Android设备来进行工作的时候,使用的读写NFC标签上数据的主要格式是NDEF。当设备扫描到带有NDEF的数据时,Android会提供对消息解析的支持,并在可能的时候,会以NdefMessage对象的形式来发送它。但是,有些情况下,设备扫描到的NFC标签没有包含NDEF数据,或者该NDEF数据没有被映射到MIME类型或URI。在这些情况下,你需要打开跟NFC标签的通信,并用自己的协议(原始的字节形式)来读写它。Android用android.nfc.tech包提供了对这些情况的一般性支持,这个包在下表1中介绍。你能够使用getTechList()方法来判断NFC标签所支持的的技术,并且用android.nfc.tech提供的一个类来创建对应的TagTechnology对象。

Table 1. Supported tag technologies (表1.NFC标签所支持的技术)

介绍

TagTechnology

所有的NFC标签技术类必须实现的接口。

NfcA

提供对NFC-A(ISO 14443-3A)属性和I/O操作的访问。

NfcB

提供对NFC-B(ISO 14443-3B)属性和I/O操作的访问。

NfcF

提供对NFC-F(ISO 6319-4)属性和I/O操作的访问。

NfcV

提供对NFC-V(ISO 15693)属性和I/O操作的访问。

IsoDep

提供对NFC-A(ISO 14443-4)属性和I/O操作的访问。

Ndef

提供对NDEF格式的NFC标签上的NDEF数据和操作的访问。

NdefFormatable

提供了对可以被NDEF格式化的NFC标签的格式化操作。

The following tag technlogies are not required to be supported by Android-powered devices.

Table 2. Optional supported tag technologies  (表2.可选的NFC标签所支持的技术)

介绍

MifareClassic

如果Android设备支持MIFARE,那么它提供了对经典的MIFARE类型标签属性和I/O操作的访问。

MifareUltralight

如果Android设备支持MIFARE,那么它提供了对超薄的MIFARE类型标签属性和I/O操作的访问。

 

2.1.1 NFC标签和ACTION_TECH_DISCOVERED类型的Intent协同工作

When a device scans a tag that has NDEF data on it, but could   not be mapped to a MIME or URI, the tag dispatch system tries to start an   activity with the ACTION_TECH_DISCOVEREDintent.   The ACTION_TECH_DISCOVERED   is also used when a tag with non-NDEF data is scanned. Having this fallback   allows you to work with the data on the tag directly if the tag dispatch   system could not parse it for you. The basic steps when working with tag   technologies are as follows:

当设备扫描到带有NDEF数据的NFC标签,但却不能映射到MIME或URI时,NFC标签调度系统就尝试使用ACTION_TECH_DISCOVERED类型的Intent来启动一个Activity。在被扫描到的NFC标签上没有NDEF数据时,也会使用ACTION_TECH_DISCOVERED类型的Intent。有了这种回退机制,如果调度系统不能够帮你解析数据,那么你就可以直接使用NFC标签上数据来工作。基本步骤如下:

      
         
    1. Filter for an ACTION_TECH_DISCOVERED         intent specifying the tag technologies that you want to handle. See Filtering for NFC intents for         more information. In general, the tag dispatch system tries to start a ACTION_TECH_DISCOVERED         intent when an NDEF message cannot be mapped to a MIME type or URI, or         if the tag scanned did not contain NDEF data. For more information on         how this is determined, see The Tag Dispatch System.
    2.   
      
         
    1. When your application receives the intent, obtain the         Tag object from the intent:
    2.   
      
         
    1. Obtain an instance of a TagTechnology, by calling one of         theget factory methods of the classes in the android.nfc.tech package. You can         enumerate the supported technologies of the tag by calling getTechList() before calling a get         factory method. For example, to obtain an instance of MifareUltralight from a Tag, do the following:
    2.   

1.   给你希望处理的NFC标签指定ACTION_TECH_DISCOVERED类型的Intent过滤器。更多信息请看“NFC的Intent过滤”。通常,在NDEF消息不能被映射到MIME类型或URI时,或者被扫描到的NFC标签不包含NDEF数据时,NFC标签调度系统会尝试启动一个ACTION_TECH_DISCOVERED类型的Intent。更多信息,请看“NFC标签调度系统”。

2. 应用程序接收到Intent对象时,从该Intent对象中获取Tag对象:

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

3.   通过调用android.nfc.tech包中对应类的一个get工厂方法,来获取一个TagTechnology对象实例。在调用get工厂方法之前,通过调用getTechList()方法来枚举NFC标签所支持的技术。例如,用下列方法从Tag对象中获取MifareUltralight对象实例:

MifareUltralight.get(intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));

 

2.1.2 读写NFC标签

Reading and writing to an NFC tag involves obtaining the tag   from the intent and opening communication with the tag. You must define your   own protocol stack to read and write data to the tag. Keep in mind, however,   that you can still read and write NDEF data when working directly with a tag.   It is up to you how you want to structure things. The following example shows   how to work with a MIFARE Ultralight tag.

读写NFC标签,要涉及到从Intent对象中获取标签,并要打开与标签的通信。要读写NFC标签数据,你必须要定义自己的协议栈。但是,要记住在直接使用NFC标签工作时,你依然能够读写NDEF数据。这是你想要如何构建的事情。下例演示了如何使用MIFARE超薄标签来工作:

package com.example.android.nfc; 

import android.nfc.Tag; 

import android.nfc.tech.MifareUltralight; 

import android.util.Log; 

import java.io.IOException; 

import java.nio.charset.Charset; 

    

publicclassMifareUltralightTagTester{ 

    

        privatestaticfinalString TAG =MifareUltralightTagTester.class.getSimpleName();
 
    

        publicvoid writeTag(Tag tag,String tagText){

                MifareUltralight ultralight =MifareUltralight.get(tag); 

                try{

                        ultralight.connect(); 

                        ultralight.writePage(4,"abcd".getBytes(Charset.forName("US-ASCII")));
 
                        ultralight.writePage(5,"efgh".getBytes(Charset.forName("US-ASCII")));
 
                        ultralight.writePage(6,"ijkl".getBytes(Charset.forName("US-ASCII")));
 
                        ultralight.writePage(7,"mnop".getBytes(Charset.forName("US-ASCII")));
 
                }catch(IOException e){ 

                        Log.e(TAG,"IOException while closing MifareUltralight...", e);
 
                }finally{ 

                        try{

                                ultralight.close(); 

                        }catch(IOException e){ 

                                Log.e(TAG,"IOException while closing MifareUltralight...", e);
 
                        } 

                } 

        } 

    

        publicString readTag(Tag tag){

                MifareUltralight mifare =MifareUltralight.get(tag); 

                try{

                        mifare.connect(); 

                        byte[] payload = mifare.readPages(4);

                        returnnewString(payload,Charset.forName("US-ASCII"));

                }catch(IOException e){ 

                        Log.e(TAG,"IOException while writing MifareUltralight 

message...", e);

                }finally{ 

                        if(mifare !=null){

                              try{

                                      mifare.close(); 

                              } 

                              catch(IOException e){

                                      Log.e(TAG,"Error closing tag...", e); 

                              } 

                        } 

                } 

                returnnull; 

        } 

} 

2.2 使用前台调度系统

The foreground dispatch system allows an activity to intercept   an intent and claim priority over other activities that handle the same   intent. Using this system involves constructing a few data structures for the   Android system to be able to send the appropriate intents to your   application. To enable the foreground dispatch system:

前台调度系统允许一个Activity拦截Intent对象,并且声明该Activity的优先级要比其他的处理相同Intent对象的Activity高。使用这个系统涉及到为Android系统构建一些数据结构,以便能够把相应的Intent对象发送给你的应用程序,以下是启用前台调度系统的步骤:

1 Add the following   code in the onCreate() method of your activity:

      
  1. Create a PendingIntent object so the Android system can populate it with the        details of the tag when it is scanned.

 PendingIntent pendingIntent   =PendingIntent.getActivity(

                 this,0,newIntent(this,   getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),0);

      
  1. Declare intent filters to handle the intents that you        want to intercept. The foreground dispatch system checks the specified        intent filters with the intent that is received when the device scans a        tag. If it matches, then your application handles the intent. If it does        not match, the foreground dispatch system falls back to the intent        dispatch system. Specifying a null array of intent filters and        technology filters, specifies that you want to filter for all tags that        fallback to the TAG_DISCOVERED intent. The code snippet below handles        all MIME types for NDEF_DISCOVERED. You should only handle the ones that        you need.

IntentFilter   ndef =newIntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);

        try{

                ndef.addDataType("*/*");   /* Handles all MIME based dispatches.

You should specify only the ones that you need. */

        }

        catch(MalformedMimeTypeException   e){

                thrownewRuntimeException("fail", e);

        }

      intentFiltersArray   =newIntentFilter[]{ndef,};

      
  1. Set up an array of tag technologies that your        application wants to handle. Call the Object.class.getName() method to        obtain the class of the technology that you want to support.

techListsArray = new String[][] { new   String[] { NfcF.class.getName() } };

 

 

 

 

1.  在你的Activity的onCreate()方法中添加下列代码:

     A.  创建一个PendingIntent对象,以便Android系统能够在扫描到NFC标签时,用它来封装NFC标签的详细信息。

          PendingIntent   pendingIntent =PendingIntent.getActivity(

                   this,0,newIntent(this,   getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP),0);

     B.  声明你想要截获处理的Intent对象的Intent过滤器。前台调度系统会在设备扫描到NFC标签时,用声明的Intent过滤器来检查接收到的Intent对象。如果匹配就会让你的应用程序来处理这个Intent对象,如果不匹配,前台调度系统会回退到Intent调度系统。如果Intent过滤器和技术过滤器的数组指定了null,那么就说明你要过滤所有的退回到TAG_DISCOVERED类型的Intent对象的标签。以下代码会用于处理所有的NDEF_DISCOVERED的MIME类型。只有在需要的时候才做这种处理:

  IntentFilter   ndef =newIntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);

        try{

                ndef.addDataType("*/*");   /* Handles all MIME based dispatches.

You   should specify only the ones that you need. */

        }

        catch(MalformedMimeTypeException   e){

                thrownewRuntimeException("fail", e);

        }

      intentFiltersArray   =newIntentFilter[]{ndef,};

     C.  建立一个应用程序希望处理的NFC标签技术的数组。调用Object.class.getName()方法来获取你想要支持的技术的类:

techListsArray = new String[][] { new String[] {   NfcF.class.getName() } };

2 Override the   following activity lifecycle callbacks and add logic to enable and disable   the foreground dispatch when the activity loses (onPause()) and regains (onResume()) focus. enableForegroundDispatch() must be   called from the main thread and only when the activity is in the foreground   (calling in onResume() guarantees this). You also   need to implement the onNewIntent callback to process the   data from the scanned NFC tag.

publicvoid onPause(){

        super.onPause();

        mAdapter.disableForegroundDispatch(this);

}

  

publicvoid onResume(){

        super.onResume();

        mAdapter.enableForegroundDispatch(this,   pendingIntent, intentFiltersArray, techListsArray);

}

  

publicvoid onNewIntent(Intent   intent){

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

        //do something with tagFromIntent

}

 

2.  重写下列Activity生命周期的回调方法,并且添加逻辑在Activity挂起(onPause())和获得焦点(onResume())时,来启用和禁用前台调度。enableForegroundDispatch()方法必须在主线程中被调用,并且只有在该Activity在前台的时候(要保证在onResume()方法中调用这个方法)。你还需要实现onNewIntent回调方法来处理扫描到的NFC标签的数据:

publicvoid onPause(){

        super.onPause();

        mAdapter.disableForegroundDispatch(this);

}

  

publicvoid onResume(){

        super.onResume();

        mAdapter.enableForegroundDispatch(this,   pendingIntent, intentFiltersArray, techListsArray);

}

  

publicvoid onNewIntent(Intent   intent){

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

        //do something with tagFromIntent

}

See the ForegroundDispatch   sample from API Demos for the complete sample

完整的示例请看API   Demo中的ForegroundDispatch

 

 

posted @ 2013-01-27 19:54 SkySeraph 阅读(...) 评论(...) 编辑 收藏