本文档描述了在Android执行的基本的NFC技术,它说明了如何发送和接收NDEF消息的形式的NFC数据,并介绍Android框架中支持这些功能的API,对于更高级的主题,包括讨论非NDEF数据相关的,参阅高级NFC文档。

当与NDEF数据和Android有关时,有两个主要的用途情况:
 
  • 从一个NFC Tag读取NDEF数据
  • 通过Android Beam™, 从一个设备到另一个设备发送NDEF消息
 
从一个NFC Tag阅读NDEF数据是Tag发布系统处理的,分析发现NFC Tag,适当地对数据进行分类,并启动一个倾向对数据进行分类的应用程序。要进行扫描NFC Tag处理的应用程序可以声明一个Intent过滤器并且请求处理数据。
 
Android Beam™功能允许设备通过跟其他设备碰在一起,把NDEF消息推到另一个设备,这种互动比其它无线技术,如蓝牙发送数据,提供了一个更简单的方法,因为NFC,没有手动装置发现或要求配对。当两个设备进入范围时连接自动启动,通过一系列的NFC API,Android Beam生效,所以任何应用都可以在设备之间传输信息,例如,联系人,浏览器和YouTube应用程序使用Android Beam与其他设备分享。联系人,网页,视频。

Tag发布系统

 
Android的设备都通常在屏幕解锁时寻找NFC Tag,除非NFC在设备的设置菜单被禁用。当Android设备扫描到一个NFC Tag,通用的行为是自动找最合适的Activity会处理这个Tag Intent而不需要用户来选择哪个Activity来处理。因为设备扫描NFC Tags是在很短的范围和时间,如果让用户选择的话,那就有可能需要移动设备,这样将会打断这个扫描过程。你应该开发你只处理需要处理的Tags的Activity,以防止让用户选择使用哪个Activity来处理的情况。
 
为了帮助你实现这个目标,Android提供了一个特殊的Tag发布系统,这个系统能分析扫描NFC Tag,解析它们,并试图找出对扫描数据有兴趣的应用程序,如下:
 
  1. 解析NFC Tag和计算出的MIME类型或一个用于在标签上确定数据有效载荷的URI。
  2. 封装的MIME类型,或者URI和有效载荷送入Intent。前两个步骤是对NFC标签如何被映射到MIME类型和URI的描述。
  3. 启动Activity的Intent。这是描述了如何发布应用NFC标签。
NFC Tag如何被映射到MIME类型和URI
 
在你开始写你的NFC应用前,了解不同类型的NFC Tag是重要的,Tag发布系统如何解析NFC Tag,以及当Tag发布系统检测NDEF消息的特殊工作。NFC Tag来源于广泛的技术,还可以有许多不同的方式对他们写入数据。Android有NDEF标准最大的支持,该标准是由NFC论坛定义的。
 
NDEF数据是在消息内封装的(NdefMessage),该消息包含一个或多个记录(NdefRecord),必须根据你要创建的特殊类型的记录来规范每个NDEF记录。Android还支持其他类型的不包含NDEF数据的Tag,你可以通过使用在android.nfc.tech包里的类来对那些DNEF有效。欲了解有关这些技术的更多信息,请参阅高级NFC的话题。使其他类型的Tag有效,包括需要编写自己的协议来和那些其他类型的Tag通信,所以我们建议当可能易于开发和采用Android的设备的最大支持时使用NDEF。
 
注意:要下载NDEF规格齐全,去NFC论坛规范下载网站,请参阅构建常见的类型的NDEF记录,例如如何构建NDEF记录。
 
现在,你已经具备了一些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_NDEF_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.
TNF_EXTERNAL_TYPE URI基于类型字段中的URN. URN是缩短的格式(<domain_name>:<service_name>.)被编码到NDEF类型中Android会把这个URN映射成以下格式的 vnd.android.nfc://ext/<domain_name>:<service_name>
TNF_MIME_MEDIA 基于类型字段的MIME类型
TNF_UNCHANGED 在第一条记录中是无效的, 因此回落到 ACTION_TECH_DISCOVERED.
TNF_UNKNOWN 回落到 ACTION_TECH_DISCOVERED.
TNF_WELL_KNOWN 依赖你在类型字段中设置的记录类型定义(RTD)的MIME类型或URI, 欲了解有效的RTDs和它们的映射更多信息,请参考表 2

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

Record类型定义 (RTD) 映射
RTD_ALTERNATIVE_CARRIER 回落到 ACTION_TECH_DISCOVERED.
RTD_HANDOVER_CARRIER 回落到 ACTION_TECH_DISCOVERED.
RTD_HANDOVER_REQUEST 回落到 ACTION_TECH_DISCOVERED.
RTD_HANDOVER_SELECT 回落到 ACTION_TECH_DISCOVERED.
RTD_SMART_POSTER 基于负载解析的URI
RTD_TEXT text/plain类型的MIME.
RTD_URI 基于负载的URI

应用程序如何调度NFC Tags

当标签调度系统完成对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,那么Tag调度系统会尝试使用这种类型的Intent来启动应用程序。如果被扫描到的标签包含了不能被映射到MIME类型或URI的NDEF数据,或者没有包含NDEF数据,但是是已知的标签技术,那么也会直接启动这种类型的Intent对象(而不是先启动ACTION_NDEF_DISCOVERED类型的Intent)
  3. ACTION_TAG_DISCOVERED: 如果没有处理 ACTION_NDEF_DISCOVEREDACTION_TECH_DISCOVERED类型Intent的Activity,就会启动这种类型的Intent。

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

  1. 用解析NFC标签时由Tag调度系统创建的Intent对象(ACTION_NDEF_DISCOVEREDACTION_TECH_DISCOVERED)来尝试启动Activity;
  2. 如果没有对应的处理Intent的Activity,那么就会尝试使用下一个优先级的Intent(ACTION_TECH_DISCOVEREDACTION_TAG_DISCOVERED)来启动Activity,直到有对应的应用程序来处理这个Intent,或者是直到Tag调度系统尝试了所有可能的Intent。
  3. 如果没有应用程序来处理任何类型的Intent,那么就不做任何事情。

图 1. Tag调度系统

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

在 Android Manifest 中申请 NFC 访问


在访问设备的NFC硬件和正确的处理NFC的Intent之前,要在AndroidManifest.xml文件中进行以下声明:
 
  • 在 <uses-permission>  元素中声明访问NFC硬件:

    <uses-permission android:name="android.permission.NFC" />
  • 你的应用程序所支持的最小的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-sdk android:minSdkVersion="10"/>
  • 使用  uses-feature 元素,在Google Play中,以便你的应用程序能够只针对有NFC硬件的设备来显示。
    <uses-feature android:name="android.hardware.nfc" android:required="true" />
     
    如果你的应用程序使用了NFC功能,但是相关的功能又不是你的应用程序的关键功能,你可以忽略uses-feature元素,并且要在运行时通过调用getDefaultAdapter()方法来检查NFC是否有效。

过滤 NFC 的 Intents


要在你想要处理被扫描到的NFC标签时启动你的应用程序,可以在你的应用程序的Android清单中针对一种、两种或全部三种类型的NFC的Intent来过滤。但是,通常想要在应用程序启动时控制最常用的ACTION_NDEF_DISCOVERED类型的Intent。在没有过滤ACTION_NDEF_DISCOVERED类型的Intent的应用程序,或数据负载不是NDEF时,才会从ACTION_NDEF_DISCOVERED类型的Intent回退到ACTION_TECH_DISCOVERED类型的Intent。通常ACTION_TAG_DISCOVERED是最一般化的过滤分类。很多应用程序都会在过滤ACTION_TAG_DISCOVERED之前,过滤ACTION_NDEF_DISCOVEREDACTION_TECH_DISCOVERED,这样就会降低你的应用程序被启动的可能性。ACTION_TAG_DISCOVERED只是在没有应用程序处理ACTION_NDEF_DISCOVEREDACTION_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()方法来获得标签所支持的技术集合。
 

举例来说,如果被扫描到的Tag支持 MifareClassic, NdefFormatable, 和 NfcA, 你的 tech-list设置 为了匹配你的activity,你必须列举出这些技术(并没有其他的)的三个,两个,或者一个.

下面的例子定义了所有的技术. 你可以删除你不需要的. 保存这个文件 (你可以用你想要的任何名字命名它)到 <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>

欲了解有关 tag 技术和 ACTION_TECH_DISCOVERED intent更详细的信息, 请参阅在高级NFC文档中的 Working with Supported Tag Technologies.

ACTION_TAG_DISCOVERED

为了过滤出 ACTION_TAG_DISCOVERED 用如下的 intent filter:

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

从 intents 获取信息

如果由于 NFC intent 导致一个activity被启动, 你可以从intent 获取关于扫描到的NFC Tag的信息. Intents包含如下附加的信息,它依赖于被扫描到的Tag:

要获取这些附加信息,就要确保你的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记录的错误。

本章也描述了如何为对应的记录创建 intent filter. 所有的 NDEF记录的例子应该在那些你写进Tag或者Beaming的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]);
先前的 NDEF 记录的 intent filter 这样表示:
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]);

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

先前的 NDEF 记录的 intent filter 这样表示:

<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 with 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 filter 这样表示:

<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_KNOWN with 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);
先前的 NDEF 记录的 intent filter 这样表示:
<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 NDEF 记录:

使用 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);
先前的 NDEF 记录的 intent filter 这样表示:
<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应用程序记录-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 filters

如果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:

  • setNdefPushMessage():  这个方法把接收到的 NdefMessage  对象作为一个消息设置给Beam。当两个设备足够近的时候,就会自动的发送消息。
  • setNdefPushMessageCallback():  接收包含 createNdefMessage() 方法的回调,当设备在发射数据的范围内时,这个回调方法会被调用。回调会让你只在需要的时候创建NDEF消息。

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

  • 发射数据的Activity必须是在前台。两个设备的屏幕都必须没有被锁定.
  • 必须发要发射的数据封装到一个 NdefMessage  对象中.
  • 接收发射数据的NFC设备必须支持 com.android.npp  推送协议或是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列表。
  3. 通常,如果你的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 应用就能够在以下情况下被启动:当扫描到NFC标签;或者接收到 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记录中嵌入标识信息,以及对应的过滤器。欲了解有关如何创建记录的更多信息请查阅Creating Common Types of NDEF records

 
 

NFC基础的更多相关文章

  1. Android训练课程(Android Training) - NFC基础

    NFC 基础 本文档介绍了在Android上的基本的NFC任务.它说明了如何发送和接收的NDEF消息(NDEF messages)的形式的表单里包含的NFC数据(NFC data),并介绍Androi ...

  2. Android近场通信---NFC基础转)

    Android近场通信---NFC基础(一)(转) 本文介绍在Android系通过你所能执行的基本任务。它解释了如何用NDEF消息格式来发送和接收NFC数据,并且介绍了支持这些功能的Android框架 ...

  3. Android近场通信---NFC基础(五)(转)

    转自 http://blog.csdn.net/think_soft/article/details/8190463 Android应用程序记录(Android Application Record- ...

  4. Android近场通信---NFC基础(四)(转)

    转自http://blog.csdn.net/think_soft/article/details/8184539 从Intent中获取信息 如果因为NFC的Intent而启动一个Activity,那 ...

  5. Android近场通信---NFC基础(三)(转)

    转自 http://blog.csdn.net/think_soft/article/details/8180203 过滤NFC的Intent 要在你想要处理被扫描到的NFC标签时启动你的应用程序,可 ...

  6. Android近场通信---NFC基础(二)(转)

    转自 http://blog.csdn.net/think_soft/article/details/8171256 应用程序如何调度NFC标签 当标签调度系统完成对NFC标签和它的标识信息封装的In ...

  7. Android近场通信---NFC基础(一)(转)

    转自 http://blog.csdn.net/think_soft/article/details/8169483 本文译自:http://developer.android.com/guide/t ...

  8. 《Android NFC 开发实战详解 》简介+源码+样章+勘误ING

    <Android NFC 开发实战详解>简介+源码+样章+勘误ING SkySeraph Mar. 14th  2014 Email:skyseraph00@163.com 更多精彩请直接 ...

  9. Android开发之深入理解NFC(一)

    深入理解NFC NFC(Near field communication,近场通信)也叫做近距离无线通信技术. 从原理来说,NFC和wifi类似,二者都利用无线射频技术来实现设备之间的通信. 但是,和 ...

随机推荐

  1. .net的五层架构

    原文章地址是http://www.360doc.com/content/11/1210/21/19147_171335782.shtml 我们刚开始学习架构的时候,首先会想到分层的概念,分层架构比较经 ...

  2. Radar Installation

    Radar Installation 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=86640#problem/C 题目: De ...

  3. 当target属性在XHTML script中无效时

    <a href="#" target=_blank></a>target此属性能够使链接在新窗口打开,但是在XHTML script中无效时. 那么解决方案 ...

  4. [CareerCup] 18.5 Shortest Distance between Two Words 两单词间的最短距离

    18.5 You have a large text file containing words. Given any two words, find the shortest distance (i ...

  5. Displaying a full list of groups in Odoo's Kanban view

    Kanban view is probably the most flexible view in Odoo. It can be used for many different purposes. ...

  6. val, lazy, def

    val strVal = scala.io.Source.fromFile("test.txt").mkString //在strVal被定义的时候获取值,如果test.txt不存 ...

  7. css形状大全

    转至:http://blog.sina.com.cn/s/blog_4abb9bba0101acsx.html

  8. HTML 几种特别分割线特效

    一.基本线条 二.特效(效果并不是孤立的,可相互组合)1.两头渐变透明:<HR style="FILTER: alpha(opacity=100,finishopacity=0,sty ...

  9. 演示save point及自治事务的用处

    1.确认数据库版本 2 举一个例子,说明save point的用处,给出SQL演示. 2.1环境准备 save point的作用是通过在事务中间设置检查点,可以更加精细的控制事务,防止一部分操作错误而 ...

  10. 20145337实验五Java网络编程及安全

    20145337实验五Java网络编程及安全 实验内容 掌握Socket程序的编写 掌握密码技术的使用 设计安全传输系统 实验步骤 基于Java Socket实现安全传输 基于TCP实现客户端和服务器 ...