首页 > 代码库 > NFC Basics(基本NFC)——翻译自developer.android.com

NFC Basics(基本NFC)——翻译自developer.android.com

NFC Basics

关于收发NDEF格式的消息,以及相关的api。

非NDEFdata以及其它更深入技术请參见Advanced NFC。


在android端使用NDEF有两种情况:
- 从标签读取NDEF数据
- 从另个android手机中使用androidBeam来获取信息。

android使用标签派发系统来处理读取NDEF数据的情况,通过分析发现的标签,给数据分类。然后启动一个关注这个分类数据的app。

应用程序能够通过注冊Intent过滤器(Intent Filter)来获取关注的标签信息。


AndroidBeam功能能够让用户给还有一台设备推送NDEF消息,只通过贴靠一下两台设备就能够完毕。这让无线交互变得比蓝牙一类的更加easy,由于使用NFC不须要手动查找设备或者配对。当两个设备靠近的时候通信就连接了。AndroidBeam能够通过一系列NFC api,所以应用都能够通过通过它在设备间交换信息。比方说联系人,浏览器,youtubeclient能够使用androidbeam来分享联系人。网页。或者视频。

标签分发系统

android设备在屏幕解锁的时候才查看NFC标签,除非NFC在设置中被关闭了。当安卓设备发现一个Tag时候。不会询问用户来选择app。而是依据intent来匹配最合适的app。

由于NFC表标签的扫描是一个非常短的过程,让用户选择app会使得设备离开标签而断开连接。你应该让你的activity直接处理它关注的标签,而不要弹出activity选择的菜单。


为了实现这个目标。android提供了一个特殊的标签分发系统,它能够扫描标签以后转化它们,然后定位匹配的app。详细是这样做的:
1. 解析标签并获得Tag的MIME类型, 或者引导数据的URI。
2.MIME类型和引导数据的URI封装成一个intent。前两个步骤在How NFC Tags are mapped to Applications介绍。

3.依据intent启动一个activity,这个的细节在How NFC Tags are Dispatched to Applications。

NFC标签是怎样映射为MIME类型或者URI的(How NFC Tag are mapped to MIME and URIs)

当你開始编程之前。你应该清楚不同的标签的种类,标签派发系统如何解析NFC标签,以及标签派发系统在探測到NDEF标签的时候所做的工作。NFC标签中包括了非常广的技术,而且数据也是以不同的方式写入的。NDEF标准是android最支持的标准,制定者为NFC Forum。

(NFC论坛)


NDEF数据别封装到一个了叫做NdefMessage的消息中,当中包括了非常多的记录。叫做NdefRecord。每个NDED记录都应该遵循你要创建的记录的类型的格式。android也支持其它不使用NDEF格式的数据标签,你能够在android.nfc.tech包中的类来帮助你处理这样的标签。

这些技术在Advanced NFC中介绍。我们推荐您使用NDEF标准。由于这样您能够更轻松地开发,而且获得android设备的最大的支持。假设使用其它的格式,您须要自定义协议栈来和标签通信。


提示:很多其它的NEDF说明,请參考NFC Forum Specification Download 站点,然后查看 Create common types of NDEF records,里面有创建NDEF记录的样例。

如今你已经有一些了解了,以下接收android如何处理 NDEF格式的标签。

当android设备扫描到包括NDEF格式数据的标签的 时候。它会解析出当中的消息,而且获取MIME类别和URI。

系统会读取NdefMessage中的第一个NdefRecord,来决定如何解析整个的NdefMessage(NdefMessage中有多个NedfRecord)。

在一个典型的NDEF格式消息里面。第一个NdefRecord包括以下几个字段:


3-bit TNF(Type Name Format 类型名格式)
  指明了解析变量边长类型字段(varible length field)的方式。数值相应的表格參见Table1。

Variable length type(变长字段类型)
描写叙述了记录的类型。假设上面使用了TNF)_WELL_KNOWN,那么这里就指明RTD。

RTD数值相应的情况请看表2。

 
变长字段的ID
关于纪律的特别指示。这个字段并不经常使用。假设你须要特别的指明一个标签。你能够为它创建一个ID。


变长字段
你真正想要读取或者写入的数据。

一个Ndef message包括非常多的Ndfe Record。所以不要以为所有数据都在第一个record里面。



标签派发系统通过TNF和类型字段来吧MINE类型或者URI映射为NDEF消息。假设成功了,就会把获得的信息和负载数据封装到一个ACTION_NDEF_DISCOVERED的里面。可是有些时候,只靠第一个ndef Record是没法推断数据类型的。

当MIME类型和URI没法映射为NDEF数据的时候。或者NFC标签不是以NDEF数据开头的。这样的情况下,会产生一个Tag对象,当中包括了标签的技术信息和数据负载,然后Tag对象被封装到了一个ACTION_TECH_DISCOVERED的intent中,而不再产生上面提到的那种Intent。


表1描写叙述了标签派法系统是如何把TNF和类型字段映射为MIME类型或者URI的。里面相同描写叙述了哪些的TNF不能被映射为MIME类型或者URI。这时标签派法系统就会会退到那个ACTION_TECH_DICOVERED的情况。


比方标签派发系统遇到了一个TNF_ABSOLUTE_URI的标签,就会把变长数据字段解释为一个URI。标签派发系统会把URI封装到一个ACTION_NDEF_DISCOVERED的intent的里面,当中还包括一些关于标签的信息。比方说数据负载。还有一方面。假设遇到了TNF_UNKNOWN类型的记录,就会创建一个封装了标签技术的intent。

Table1 表1 支持的TNF以及它们的相应信息

Type Name Format (TNF)Mapping
TNF_ABSOLUTE_URIURI based on the type field.
TNF_EMPTYFalls back to ACTION_TECH_DISCOVERED.
TNF_EXTERNAL_TYPEURI based on the URN in the type field. The URN is encoded into the NDEF type field in a shortened form: <domain_name>:<service_name>. Android maps this to a URI in the form: vnd.android.nfc://ext/<domain_name>:<service_name>.
TNF_MIME_MEDIAMIME type based on the type field.
TNF_UNCHANGEDInvalid in the first record, so falls back to ACTION_TECH_DISCOVERED.
TNF_UNKNOWNFalls back to ACTION_TECH_DISCOVERED.
TNF_WELL_KNOWNMIME type or URI depending on the Record Type Definition (RTD), which you set in the type field. See Table 2. for more information on available RTDs and their mappings.

Table 2. Supported RTDs for TNF_WELL_KNOWN and their mappings

Record Type Definition (RTD)Mapping
RTD_ALTERNATIVE_CARRIERFalls back to ACTION_TECH_DISCOVERED.
RTD_HANDOVER_CARRIERFalls back to ACTION_TECH_DISCOVERED.
RTD_HANDOVER_REQUESTFalls back to ACTION_TECH_DISCOVERED.
RTD_HANDOVER_SELECTFalls back to ACTION_TECH_DISCOVERED.
RTD_SMART_POSTERURI based on parsing the payload.
RTD_TEXTMIME type of text/plain.
RTD_URIURI based on payload.

NFC标签是怎样派发给应用的

当标签标签派发系统已经创建了封装了关于标签的信息和指示信息的intent以后。就会把它传递给过滤这样的intent的应用。

假设多个应用都过滤(这里是要筛子上面的东西,能够理解为筛选,而不是漏出去的——小马)了这样的intent,就会出现activity选择器供用户选择activity。标签派发系统定义三种类型的标签,以下依照优先级从高到低排序。

1. ACTION_NDEF_DISCOVERED: 这个intent用来在发现标签中包括NDEF格式的负载而且当中的类型是已知的情况下,启动一个activity。这样的intent优先级最高。标签派发系统一旦可能就最先发出这样的。

2.ACTION_TECH_DISCOVERED:假设没有应用注冊捕获ACTION_NDEF_DISCOVERED的intent,那么系统就会启动这样的intent。在NDEF类型的数据不能映射为MIME类型或者URI的时候,也会直接发出这样的类型的intent(之前没有发出ndef那种),或者标签中不包括NDEF的数据而而是一种已知的标签技术。也会用这样的intent。
3.ACTION_TAG_DISCOVERED:假设前两者intent么有被捕获。那么就启动这样的intent。

标签派法系统基本工作方式例如以下:

1.解析NFC tag的时候发出一个intent来启动一个activity。(指的是CTION_NDEF_DISCOVERED和ACTION_TECH_DISCOVERED )。

2.假设没有activity捕获这个intent。就使用下一个优先级的intent来启动activity(ACTION_TECH_DISCOVERD或者ACTION_TAG_DISCOVERED),假设没有捕获就启动下一个优先级的 intent。

3.如过最后也没有 捕获,就什么也不做。
技术分享
图1.标签派法系统
仅仅要有可能,就启动NDEF的intent,由于这是三种之中最特殊的,这样的intent能够让你更恰当地启动app,给用户更好的体验。


在Android Manifest中获取NFC訪问
在你能够訪问NFC硬件设备和处理NFCintent之前,在你的AndroidManifest.xml中声明例如以下:
- 訪问NFC硬件的<uses-permission>元素
  • <uses-permission android:name="android.permission.NFC" />

- 你的应用支持的最小的sdk。api level 9只通过ACTION_TAG_DISCOVERED支持有限的标签派发功能,通过EXTRA_NDEF_MESSAGES能够訪问NDEF格式信息。其它的标签属性訪问和IO操作都不支持。

API level 10包括了广泛的读写操作的支持,还有前台的NDEF推送,API level14 提供了给其它设备推送NDEF消息的便捷办法,通过Android Beam和其它的创建NDEFrecords的便捷的方法。

<uses-sdk android:minSdkVersion="10"/>
- uses-feature 元素,在应用商店里面指示你的应用仅仅能在NFC设备上面执行。

<uses-feature android:name="android.hardware.nfc" android:required="true" />
假设你的应用仅仅是把nfc作为一个可选功能,那么你能够忽略uses-feature元素,而且在执行时候查看设备是是否支持nfc。

比方通过方法getDefaultAdapter是不是空的。


筛选NFC Intent Filtering for NFC Intents


你的应用在扫描到NFC标签的时候启动。应该在你的应用中加入一种。两种。或者三种所有类型的intent筛选。就在Android Manifest中。然而通常都是倾向于把ACTION_NDEF_DISCOVERED作为启动你应用的选项。

ACTION_TECH_DISCOVERED是第一种没有不论什么应用处理或者负载不是NDEF格式的时候的备选项。

而使用ACTION_TAG_DISCOVERED则会导致筛选太宽泛。

多数的应用都会依照优先级。先使用头两种。这样不会使得你的应用启动的太过频繁。TAG的intent作为最后的选择,在前面两种都没有应答的时候才使用。


由于NFC标签的部署种类非常多样,并且也大都不在你的控制之下。所以这是你须要使用另外两种备选intent的原因。假设标签的写入部分在你的控制下。那么推荐你使用NDEF来作为标签的格式。

以下的部分展示了如何筛选不同类型的intent。



ACTION_NDEF_DISCOVERED

要筛选这个类型的intent,须要声明这个类型。和数据的类型以下这个样例就指定了ACTION_NDEF_DISCOVERED的筛选。和 text/plain的MIME类型。


<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="text/plain" />
</intent-filter>
以下是一种URI形式的筛选。

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_TECH_DISCOVERED

假设你的activity筛选了ACTION_TECCH_DISCOVERED intent,你必须同一时候使用一个 tech-list集来创建一个xml文件,指明你的应用支持哪些的技术类型。假设你的支持的技术集是标签中支持的技术的子集,那么就会匹配。你能够使用getTechList()来获取标签支持的类型。

举个样例。假设一个扫描的标签支持了MifareClassic,NdefFormatable。和NfcA,你的activity的筛选器的tech-list里面要支持三种中的至少一种。

以下是一个定义了全部的技术的tech-list的样例。你能够把你不须要的删掉。把这个文件存储在项目的根文件夹/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集合。每个集合都作为独立的,你的不论什么的一个list中的技术是getTechList方法返回的标签中包括的技术的子集的时候。就觉得匹配成功。这里面就是AND与和OR或的语意来匹配技术的。以下是一个吃吃NfcA和Ndef技术,或者支持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_TECH_DISCOVERED intent的很多其它的信息。请參加Working with Supported Tag Technologies,Advance NFC文档。

ACTION_TAG_DISCOVERED

这个标签的过滤器例如以下。

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

从intent中获取信息 Obtaining information from intents

假设一个app是通过NFC intent启动的,那么能够从intent中获取扫描到的标签的信息。不同的标签可能包括下面的额外信息,extras。
- EXTRA_TAG(必有的):代表标签的Tag类对象。

- EXTRA_NDEF_MESSAGES(可选的):从标签中解析出来的NDEF message数组。在ACTION_NDEF_DISCOVERED的intent中是必须的。
- EXTRA_ID(可选):标签的底层的ID。

要先检查你应用是不是由NFC intent启动的。然后再从中获取这些额外信息。以下是一个检查 ACTION_NDEF_DISCOVERED intent并获取额外信息的方法样例:


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记录  Creating Common Types of NDEF Records


这个部分讲述怎样在你写入标签或者AndroidBeam通信的时候怎样创建典型的NDEF记录。从Android 4.0,即API 14開始,你能够使用createUri来自己主动帮你创建URI类型。

从Android4.1,即API 16開始,能够使用creatExternal或者createMine来创建MIME和其它的NDEF类型的record。尽量使用这些便捷的方式来避免手动创建NDEFrecord可能会发生的错误。


这部分还讲述了如何创建与record相应的筛选器。当写入标签或者Android Beam时。全部NDEFrecord的样例都应该在NDEF message的第一个NDEF record中。


TNF_ABSOLUTE_URI

提示:我们推荐您使用更高效的RTD_URI来替代TNF_ABSOLUTE_URI。


能够使用以下的方法创建一个TNF_ABSOLUTE_URI NDEF record。

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 record:
使用createMine()方法:
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  record的过滤器如以下这样。

<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

能够使用例如以下方法创建record:

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

使用高级方法1
NdefRecord rtdUriRecord1 = NdefRecord.createUri("http://example.com");
使用高级方法2
Uri uri = new Uri("http://example.com");
NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);
手动创建
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-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

使用高级方法:Using the createExternal() method:

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:

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

过滤器:

<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:nfc:ext:example.com:externalType,可是NFC Forum RTD说明书里面声明了: urn:nfc:ext: 的urn部分必须从NDEF record的格式中省略。

所以你仅仅须要提供一个域(比方说 样例中的example.com)和一个类型(比方说样例中的 externalType)就能够了。中间用冒号连接。

当派发TNF_EXTERNAL_TYPE类型的时候,Android会将urn:nfc:ext:example.com:externalType的urn转化为vnd.android.nfc://ext/eample.com:externalType 的URI,就是样例中的intent过滤器中定义的那样。



Android应用记录 Android Application Records

AAR在Android4.0中引入,目的是为了在扫描到标签时保证app会被启动。

AAR在NDEFrecord中嵌入了一个应用的包名。

你能够把AAR增加到NDEF message的不论什么一个NDEFrecord其中,由于android会扫描NDEF message中的每个NDEFrecord来寻找AAR。假设找到了就会基于AAR之中的包名来启动app。

假设如今设备里面没有这个app,就执行GooglePlay来開始下载app。


AAR能够帮助你来防止其它的应用筛选相同的intent。而且能够让你的特定的标签。AAR仅仅在app的级别被支持,由于使用了包名进行约束。而不是activity中的筛选器,假设想要activity界别的支持。请使用intent筛选器。


付过一个标签包括了AAR,标签派法系统依照以下的方式来执行:
1. 像之前一样用intent来启动一个activity,假设匹配了intent的activity也匹配了AAR,那么就启动Activity。

2.假设匹配了intent的acitivity的应用不匹配AAR,或者假设多个activity都能够拦截intent。或者假设没有Activity拦截这个intent,就启动AAR中指定的app。

3.假设没有应用能够匹配AAR,就去GooglePlay中下载在AAR中指定的application。


提示:你能够使用前台派发系统来覆盖AAR和intent派发系统,也就是说让一个前台的activity拥有获得NFC标签的优先级。使用这样的方法,一个应用必需要在前台才干覆盖AAR和intent派发系统。

假设你还想使用filter来过滤不含有AAR的标签,你就能够想之前那样定义intent filter。这在你的应用想要捕获其它的不含有AAR的intent的时候非常管用。举个样例,可能你会想保证让你的应用优先捕获AAR指定你的应用的intent,其次还想捕获其它感兴趣的第三方标签。记住AAR仅仅在4.0和以后的版本号中支持,所以在部署你的标签的时候,使用AAR和MIME类型/URI结合的方式。能够让你的标签被很多其它种类的设备支持。另外。部署标签的时候,思考如何能够支持很多其它的设备是非常重要的。比方说android设备和非安卓的设备。你能够通过定义一个相关的特别的MIME类型或者URI来让app更easy别识别出来。


Android 提供了一个创建AAR的简便的方法,createApplicationRecord()。你须要咬做的就是就是在你的NdefMessage到处嵌入AAR。

除非AAR是你的NedfMessage中的唯一的record,否则不要把AAR放在NdefMessage的第一个record。这是由于android系统第一个记录来推断MIME类型和标签的URI。

MIME和URI是用来产生给过滤器的intent的。

以下是一个创建AAR的样例:

NdefMessage msg = new NdefMessage(
        new NdefRecord[] {
            ...,
            NdefRecord.createApplicationRecord("com.example.android.beam")}
向其它设备发送(Beam)NDEF消息  Beaming NDEF Messages to Other Devices
AndroidBeam能够让两个Android设备传送P2P的消息。

发起Beam的应用一定要在设备的前台,而接收Beam的设备应该解锁屏幕。当发起设备和接收设备的距离足够近的时候。发起的 设备会出现“点击開始Beam传送的提示”。使用者能够选择是不是Beam给接收设备信息。


提示:前台的NDEF推送在API 10以上才可用。它的功能和Android Beam类似。这个API如今已经被弃用了,可是在老设备上支持。

很多其它请參见enableForegoundNdefPush方法。


你能够用下面两种方法来开启你的Android Beam:

- setNdefPushMessage:接收一个NdefMessage对象作为传送的消息。在两个设备足够接近的时候会自己主动启动传送消息。

- setNedfPushiMessageCallback():接收一个包括createNdefMessage的回调,createNdefMessage就是上面的那个。 回调方法让你仅仅有在必要的时候才创建NDEF message。

一个设备一次仅仅能推送一个NDEF message,所以当两个都是设置的时候。CallBack方法比前者有更高的优先级。

使用Android Beam你还要知道以下几个经验:


- 主动设备的activity要前台,被动设备要解锁。
- 仅仅能使用NdefMessage封装你的消息。

- 被动设备要支持 com.android.npp NDEF推送协议,或者 NFC Forum的SNEP(简单 NDEF交换协议)。android2.3 api9到andro3.2 api13须要 com.android.npp协议,在4.0 api14以后com.android.npp和SNEP两种都须要。


提示:假设你的支持Android Beamactivity在前台,你的标准的intent派发系统就会停用。

假设你的activity也开启了“前台派发”,那么仍然能够捕获在“前台派发”中设置的intent过滤器。


要使用Android Beam的过程例如以下:
1.创建一个包换你想推送的NdefRecord的Ndef Message。
2.在你的activity的onCreate方法中调用setNdefPushMessage方法并传入NdefMessage參数,或者调用setNdefPushMessageCallback方法。传入NfcAdaper.CreateNdefMessgeCallback对象。在你想要使用AndroidBeam的至少一个activity中,你应该调用这些方法。而且能够选择附上一个其它想激活功能的activity的可选的列表。
通常来讲,假设你想在每次都推送同样的NDEF 方法,你能够使用setNdefPushMessage()方法。

当你的应用要依据当前的上下文来决定推送什么样的消息的时候。就应该使用setNdefPushMessageCallback方法。这样会更加依赖于你的用户在应用中正在做什么。


以下是一个简单的调用NfcAdapter.CreateNdefMessageCallback的activity的样例。

在activity中onCreate方法中调用,能够在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的应用就会接到AndroidBeam消息。 假设如今没有这个应用就会从Google Play中下载。这种话,在技术上讲,对于Android4.0以后的设备使用AAR就没有必要使用以下的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标签或者收到了一个包括AAR com.example.android.beam 类型的Android Beam。或者一个NDEF格式的消息中包括了application/vnd.com.example.android.beam类型的 MIME记录。


进骨干AAR保证了应用被启动或者被下载,可是仍然推荐intent filter。由于这样能够启动一个activity而不是一个app中的主activity。

AAR没有activity级别的标志。

而且另一些设备不支持AAR,你应该仍然在NDEFmessage的第一个NDEFRecord中嵌入指示信息,而且用过滤器来获取。以防万一。创建record的方法详情请參见Creating common Types fo NDEF records。


NFC Basics(基本NFC)——翻译自developer.android.com