Android近场通讯---NFC基础转)

Android近场通讯---NFC基础(一)(转)

本文介绍在Android系经过你所能执行的基本任务。它解释了如何用NDEF消息格式来发送和接收NFC数据,而且介绍了支持这些功能的Android框架API。有关更高级的话题,包括对非NDEF格式数据的讨论,状况“高级 NFChtml

NDEF数据和Android一块儿工做的场景主要有两个:java

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

2.  把NDEF消息从一个设备发送给另外一个设备。数组

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

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

NFC标签调度系统框架

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

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

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

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

3.  基于Intent来启动Activity。

怎样把NFC标签映射到MIME类型和URI

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

NDEF数据被封装在一个消息(NdefMessage)中,该消息中包含了一条或多条记录(NdefRecord)。每一个NDEF记录必须具备良好的你想要建立的记录类型的规范的格式。Android也支持其余的不包含NDEF数据类型的标签,你可以使用android.nfc.tech包中的类来工做。要使用其余类型标签来工做,涉及到编写本身的跟该标签通讯的协议栈,所以咱们建议你尽量的使用NDEF,以便减小开发难度,而且最大化的支持Android设备。

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

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

3-bit TNF(类型名称格式)

指示如何解释可变长度类型字段,在下表1中介绍有效值。

可变长度类型

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

可变长度ID

惟一标识该记录。这个字段不常用,可是,若是须要惟一的标识一个标记,那么就能够为该字段建立一个ID。

可变长度负载

你想读/写的实际的数据负载。一个NDEF消息可以包含多个NDEF记录,所以不要觉得在NDEF消息的第一条NDEF记录中包含了全部的负载。

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

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

例如,若是标签调度系统遇到一个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

 

 
 

Android近场通讯---NFC基础(二)(转)

应用程序如何调度NFC标签

当标签调度系统完成对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。

 

标签调度系统的基本工做方法以下:

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,那么就不作任何事情。

图1.标签调度系统

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

 

在Android的Manifest中申请NFC访问

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

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"/>

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

 

Android近场通讯---NFC基础(三)(转)

过滤NFC的Intent

要在你想要处理被扫描到的NFC标签时启动你的应用程序,能够在你的应用程序的Android清单中针对一种、两种或所有三种类型的NFC的Intent来过滤。可是,一般想要在应用程序启动时控制最经常使用的ACTION_NDEF_DISCOVERED类型的Intent。在没有过滤ACTION_NDEF_DISCOVERED类型的Intent的应用程序,或数据负载不是NDEF时,才会从ACTION_NDEF_DISCOVERED类型的Intent回退到ACTION_TECH_DISCOVERED类型的Intent。一般ACTION_TAB_DISCOVERED是最通常化的过滤分类。不少应用程序都会在过滤ACTION_TAG_DISCOVERED以前,过滤ACTION_NDEF_DISCOVERED或ACTION_TECH_DISCOVERED,这样就会下降你的应用程序被启动的可能性。ACTION_TAG_DISCOVERED只是在没有应用程序处理ACTION_NDEF_DISCOVERED或ACTION_TECH_DISCOVERED类型的Intent的状况下,才使用的最后手段。

由于NFC标签的多样性,而且不少时候不在你的控制之下,所以在必要的时候你要回退到其余两种类型的Intent。在你可以控制标签的类型和写入的数据时,咱们建议你使用NDEF格式。下文将介绍如何过滤每种类型的Intent对象。

ACTION_NDEF_DISCOVERED

要过滤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>

ACTION_TECH_DISCOVERED

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

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

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

<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>

你也可以指定多个tech-list集合,每一个tech-list集合被认为是独立的,而且若是任何一个tech-list集合是由getTechList()返回的技术的子集,那么你的Activity就被认为是匹配的。下列示例可以跟支持NfcA和Ndef技术NFC标签或者跟支持NfcB和Ndef技术的标签相匹配:

<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>

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

<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>

ACTION_TAG_DISCOVERED

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

<intent-filter>

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

</intent-filter>

 

Android近场通讯---NFC基础(四)(转)

从Intent中获取信息

若是由于NFC的Intent而启动一个Activity,那么你就可以从Intent中获取被扫描到的NFC标签的相关信息。根据被扫描到的标签,Intent对象可以如下额外的信息:

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

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

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

要获取这些附加信息,就要确保你的Activity是被扫描到的NFC的Intent对象启动的,而后才能得到Intent以外的附加信息。下例检查ACTION_NDEF_DISCOVERED类型的Intent,并从Intent对象的附加信息中获取NDEF消息。

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

}

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

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

建立通用的NDEF记录类型

本节介绍如何建立通用的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消息的第一条记录。

TNF_ABSOLUTE_URI

注意:咱们推荐你使用RTD_URI类型,而不是TNF_ABSOLUTE_URI,由于它更高效。

用下列方法建立一个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]);

对应的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>

TNF_MIME_MEDIA

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

使用createMime()方法:

NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam",

"Beam me up, Android".getBytes(Charset.forName("US-ASCII")));

手动的建立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")));

对应的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>

 

TNF_WELL_KNOWN和RTD_TEXT

用下列方法建立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;

}

对应的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>

 

TNF_WELL_KNOW和RTD_URI

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

使用createUri(String)方法:

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

使用createUri(Uri)方法:

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

NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);

手动的建立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);

对应的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>

TNF_EXTERNAL_TYPE

使用下列方法建立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);

手动的建立NdefRecord:

byte[] payload;

...

NdefRecord extRecord = new NdefRecord(

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

对应的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>

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

注意: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过滤器。

 

Android近场通讯---NFC基础(五)(转)

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

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

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

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

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

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

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

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

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

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")}

 

把NDEF消息发射到其余设备上

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

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

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

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

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

一个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都须要。

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

启用Android Beam:

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

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

一般,若是你的Activity在任什么时候候都值推送相同的NDEF消息,那么当两个设备在通讯范围内的时候,使用setNdefPushMessage()就能够了。当你的应用程序要关注应用程序的当前内容,并想要根据用户在你的应用程序中的行为来推送NDEF消息时,就要使用setNdefPushMessageCallback方法。

下列示例代码演示了如何在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;

public class Beam extends Activity implements CreateNdefMessageCallback {

    NfcAdapter mNfcAdapter;

    TextView textView;

    @Override

    public void 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

    public NdefMessage createNdefMessage(NfcEvent event) {

        String text = ("Beam me up, Android!\n\n" +

                "Beam Time: " + System.currentTimeMillis());

        NdefMessage msg = new NdefMessage(

                new NdefRecord[] { 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

    public void 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

    public void 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(new String(msg.getRecords()[0].getPayload()));

    }

}

注意:上例代码把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>

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

1.  扫描到NFC标签;

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

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

相关文章
相关标签/搜索