`
810364804
  • 浏览: 786858 次
文章分类
社区版块
存档分类
最新评论

NFC基础

 
阅读更多

本文档描述了在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是在很短的范围和时间,如果让用户选择的话,那就有可能需要移动设备,这样将会打断这个扫描过程。你应该开发你只处理需要处理的TagsActivity,以防止让用户选择使用哪个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_DISCOVEREDintent更详细的信息, 请参阅在高级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_URINDEF 记录:

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这样表示:
<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_MEDIANDEF 记录.

使用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_KNOWNNDEF 记录:

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_KNOWNNDEF 记录.

使用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_TYPENDEF 记录:

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

一个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. 创建一个准备推送到另一个设备上的包含NdefRecordNdefMessage对象
  2. 调用带有NdefMessage类型参数的setNdefPushMessage()方法,或者是在Activity的onCreate()方法中调用setNdefPushMessageCallback方法来传递实现NfcAdapter.CreateNdefMessageCallback接口的对象。这两个方法都至少需要一个准备要启用Android Beam的Activity,以及一个可选的其他的活跃的Activity列表。
  3. 通常,如果你的Activity在任何时候都值推送相同的NDEF消息,那么当两个设备在通信范围内的时候,使用setNdefPushMessage()就可以了。当你的应用程序要关注应用程序的当前内容,并想要根据用户在你的应用程序中的行为来推送NDEF消息时,就要使用setNdefPushMessageCallback方法。
下列示例代码演示了如何在activityonCreate()方法中调用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标签/收发器应用与设计(ST提供,Part1:NFC基础)-Part-1-NFC应用与基础知识.pdf

    NFC标签/收发器应用与设计(ST提供,Part1:NFC基础)-Part-1-NFC应用与基础知识.pdf

    Android近场通信---NFC基础.doc

    Android近场通信---NFC基础

    Android近场通信---NFC基础

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

    NFC软件基础 NFC软件基础

    NFC软件基础

    NFC协议 Digital部分

    nfc基础协议 NFC Data Exchange Format (NDEF) Technical Specification 部分。

    为安全移动支付的NFC技术.pdf

    NFC基础知识和市场 加密简介 使用NFC的安全移动支付 问题 结论

    Android NFC开发实战详解.part1(共两份,此为第一份)

    [Android NFC开发实战详解]_赵波编著.人民邮电出版社.2014.05.扫描版 本PDF为完整扫描版,非电子样章,本书已添加书签。 此资源已分包压缩成了两份,此为第一份,请全部下载后再解压,否则会解压失败。本资源仅第一...

    nfc_NFC技术_java_nfc读卡源码_NFC_

    NFC读卡信息的例子源码,NFC技术由非接触式射频识别(RFID)演变而来,由飞利浦半导体(现恩智浦半导体)、诺基亚和索尼共同研制开发,其基础是RFID及互连技术

    NFC 技术--移动通讯设备应用

    介绍NFC基础的开发,模式和背后协议规则支持。 着重介绍的NFC在移动通讯设备中的应用

    cloud 4700读卡器使用手册

    Identive Cloud 4700F可以支持兼容ID1尺寸的卡片,智能钥匙,各种规格密钥,NFC电子标签 和 支持NFC的智能手机,被广泛应用于网络登入,基于WEB的安全交易 和以NFC基础会员计划。 Identive Cloud 4700F 双界面读写器主要...

    react-native-nfc:该项目的目标是使扫描NFC标签和读取其中包含的NDEF记录变得容易(或更容易)。

    读取React Native的NFC标签(仅Android) 该项目的目标是使扫描NFC标签和...花一点时间阅读有关NFC基础知识的,尤其是“ 部分。 编辑文件AndroidManifest.xml 添加读取NFC数据的权限: 将以下属性添加到您的部分,

    NFC近场通信技术.pdf

    NFC近场通信技术.pdf

    NFC测试标准

    这个技术由非接触式射频识别(RFID)演变而来,由飞利浦半导体(现恩智浦半导体)、诺基亚和索尼共同研制开发,其基础是RFID及互连技术。近场通信(Near Field Communication,NFC)是一种短距高频的无线电技术,在...

    NFC技术研究论文,可拷贝

    介绍了NFC技术及应用,NFC技术研究论文,可拷贝,可参考,可引用,适用于初期研究者参考、学习,了解NFC技术基础

    rfid_nfc.7z

    Android使用NFC读取数据,近距离无线通讯技术,这个技术由非接触式射频识别(RFID)演变而来,由飞利浦半导体(现恩智浦半导体公司)、诺基亚和索尼共同研制开发,其基础是RFID及互连技术。近场通信(Near Field ...

    详解Android平台上读写NFC标签

    一、NFC基础知识 1.NFC是什么? NFC,即Near Field Communication,近距离无线通讯技术,是一种短距离的(通常&lt;=4cm或更短)高频(13.56M Hz)无线通信技术,它提供了一种简单、触控式的解决方案,可以让消费者...

    Android例子源码NFC读卡信息小例子

    本例子是一个NFC读卡信息的例子源码,NFC技术由非接触式射频识别(RFID)演变而来,由飞利浦半导体(现恩智浦半导体)、诺基亚和索尼共同研制开发,其基础是RFID及互连技术。近场通信(Near Field Communication,NFC...

    Android例子源码NFC读卡信息小例子源码.zip

    本例子是一个NFC读卡信息的例子源码,NFC技术由非接触式射频识别(RFID)演变而来,由飞利浦半导体(现恩智浦半导体)、诺基亚和索尼共同研制开发,其基础是RFID及互连技术。近场通信(Near Field Communication,NFC...

    NFC读卡信息小例子源码.zip

    NFC读卡信息小例子源码,NFC技术由非接触式射频识别(RFID)演变而来,由飞利浦半导体(现恩智浦半导体)、诺基亚和索尼共同研制开发,其基础是RFID及互连技术。近场通信(Near Field Communication,NFC)是一种短距...

Global site tag (gtag.js) - Google Analytics