学习笔记-翻译资料:Android 2.3.3 近场通讯NFC介绍

NFC(近场通讯)html

NFC是一套短距离的无线通讯,一般距离是4厘米或更短。NFC工做频率是13.56M Hz,传输速率是106kbit/s 848kbit/s. NFC老是在一个发起者和一个被动目标之间发生。发起者发出近场无线电波,这个近场能够给被动目标供电。这些被动的目标包括不须要电源的标签,卡,也能够是有电源的设备。java

与其余无线通讯技术比较, 例如蓝牙和WiFi NFC提供更低带宽和距离,而且低成本,不须要供电,不须要实现匹配,整个通讯过程仅仅是短短的靠近一秒就能完成。android

一个带有NFC支持的android设备一般是一个发起者。也能够做为NFC的读写设备。他将检测NFC tags而且打开一个Activity来处理. Android 2.3.3还有支持有限的P2Papi

Tags分不少种,其中简单的只提供读写段,有的只能读。复杂的tags能够支持一些运算,加密来控制对tags里数据段的读写。甚至一些tags上有简单的操做系统,容许一些复杂的交互和能够执行一些代码。数据结构

API概览app

Android.nfc  package包含顶层类用来与本地NFC适配器交互. 这些类能够表示被检测到的tags和用NDEF数据格式。ide

Classui

Descriptionthis

NfcManager加密

一个NFC adapter的管理器,能够列出全部此android设备支持的NFC adapter.只不过大部分android 设备只有一个NFC adapter,因此你大部分状况下能够直接用静态方法 getDefaultAdapter(context)来取适配器。

NfcAdapter

表示本设备的NFC adapter,能够定义Intent来请求将系统检测到tags的提醒发送到你的Activity.并提供方法去注册前台tag提醒发布和前台NDEF推送。 前台NDEF推送是当前android版本惟一支持的p2p NFC通讯方式。

NdefMessage and NdefRecord

NDEFNFC论坛定义的数据结构,用来有效的存数据到NFC tags.好比文本,URL,和其余MIME类型。一个NdefMessage扮演一个容器,这个容器存哪些发送和读到的数据。一个NdefMessage对象包含或多个NdefRecord,每一个NDEF record有一个类型,好比文本,URL,智慧型海报/广告,或其余MIME数据。在NDEFMessage里的第一个NfcRecord的类型用来发送tag到一个android设备上的activity.

Tag

标示一个被动的NFC目标,好比tagcard,钥匙挂扣,甚至是一个电话模拟的的NFC.

当一个tag被检测到,一个tag对象将被建立而且封装到一个Intent里,而后NFC 发布系统将这个IntentstartActivity发送到注册了接受这种Intentactivity里。你能够用getTechList()方法来获得这个tag支持的技术细节和建立一个android.nfc.tech提供的相应的TagTechnology对象。

android.nfc.tech package 包含那些对tag查询属性和进行I/O操做的类。这些类分别标示一个tag支持的不一样的NFC技术标准。

Class

Description

TagTechnology

这个接口是下面全部tag technology类必须实现的。

NfcA

支持ISO 14443-3A 标准的操做。Provides access to NFC-A (ISO 14443-3A) properties and I/O operations.

NfcB

Provides access to NFC-B (ISO 14443-3B) properties and I/O operations.

NfcF

Provides access to NFC-F (JIS 6319-4) properties and I/O operations.

NfcV

Provides access to NFC-V (ISO 15693) properties and I/O operations.

IsoDep

Provides access to ISO-DEP (ISO 14443-4) properties and I/O operations.

Ndef

提供对那些被格式化为NDEFtag的数据的访问和其余操做。

Provides access to NDEF data and operations on NFC tags that have been formatted as NDEF.

NdefFormatable

对那些能够被格式化成NDEF格式的tag提供一个格式化的操做

MifareClassic

若是android设备支持MIFARE,提供对MIFARE Classic目标的属性和I/O操做。

MifareUltralight

若是android设备支持MIFARE,提供对MIFARE Ultralight目标的属性和I/O操做。

声明Android Manifest.xml的元素

在你能访问一个设备的NFC硬件和正确的处理NFCIntent以前,须要在AndroidManifest.xml中先声明下面的项:

1.     NFC使用 <uses-permission> 元素来访问NFC硬件:

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

2.     最小SDK版本须要设置正确,API level 9只包含有限的tag支持,包括:
    .
经过ACTION_TAG_DISCOVERED来发布Tag信息
    .
只有经过EXTRA_NDEF_MESSAGES扩展来访问NDEF消息
    .
其余的tag属性和I/O操做都不支持
因此你可能想要用API level 10来实现对tag的普遍的读写支持。

<uses-sdk android:minSdkVersion="10"/>

3.     uses-feature 元素定义:你的程序能够再android市场里显示有NFC硬件。

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

4.      NFC intent filter告诉android系统你的activity能处理NFC数据,能够定义1个或多个intent filter:

<intent-filter>
  <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
  <data android:mimeType="mime/type" />
</intent-filter>

<intent-filter>
  <action android:name="android.nfc.action.TECH_DISCOVERED"/>
  <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
                android:resource="@xml/nfc_tech_filter.xml" />
</intent-filter>

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

上边3intent filters 有优先级,更多信息能够看下面的Tag发布系统

也能够看NFCDemo例子的 AndroidManifest.xml来有个更深的理解。

Tag发布系统

android设备扫描到一个NFC tag,通用的行为是自动找最合适的Activity会处理这个tag Intent而不须要用户来选择哪一个Activity来处理。由于设备扫描NFC tags是在很短的范围和时间,若是让用户选择的话,那就有可能须要移动设备,这样将会打断这个扫描过程。你应该开发你只处理须要处理的tagsActivity,以防止让用户选择使用哪一个Activity来处理的状况。Android提供两个系统来帮助你正确的识别一个NFC tag是不是你的Activity想要处理的:Intent发布系统和前台Activity发布系统。

Intent发布系统检查全部Activitiesintent filters,找出那些定义了能够处理此tagActivity,若是有多个Activity都配置了处理同一个tag Intent,那么将使用Activity选择器来让用户选择使用哪一个Activity。用户选择以后,将使用选择的Activity来处理此Intent.

前台发布系统容许一个Activity覆盖掉Intent发布系统而首先处理此tag Intent,这要求你将要处理Tag IntentActivity运行在前台,这样当一个NFC tag被扫描到,系统先检测前台的Activity是否支持处理此Intent,若是支持,即将此Intent传给此Activity,若是不支持,则转到Intent发布系统。

使用Intent发布系统

Intent发布系统指定了3intent有不一样的优先级。一般当一个tag被检测到以后,Intent就被启动(start)了,这个启动遵循如下行为:

·         android.nfc.action.NDEF_DISCOVERED: 这个intent是在一个包含NDEF负载的tag被检测到时启动,这是最高优先级的intent, android系统不会让你指定一个Intent能处理全部的NFC数据类型,你必须在AndroidManifest.xml中指定与NFC tag对应的<data>元素,这样当扫描到的tag传过来的数据类型与你定义的相匹配时,你的Activity就会被调用。例如想处理一个包含plain text NDEF_DISCOVERED intent ,你要按照以下定义AndroidManifest.xml file:

<intent-filter>
    <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
    <data android:mimeType="text/plain" />
</intent-filter>

若是NDEF_DISCOVERED intent 已经被启动,TECH_DISCOVERED TAG_DISCOVERED intents 将不会被启动。假如一个未知的tag或者不包含NDEF负载的tag被检测到,此Intent就不会被启动。

·         android.nfc.action.TECH_DISCOVERED: 若是 NDEF_DISCOVERED intent没启动或者没有一个Activityfilter检测NDEF_DISCOVERED ,而且此tag是已知的,那么此TECH_DISCOVERED Intent将会启动. TECH_DISCOVERED intent要求你在一个资源文件里(xml)里指定你要支持technologies列表。更多细节请看下面的Specifying tag technologies to handle.

·         android.nfc.action.TAG_DISCOVERED: 若是没有一个activity处理_DISCOVERED and TECH_DISCOVERED intents或者tag被检测为未知的,那么此Intent将会被启动。

Specifying tag technologies to handle指定处理的technologies

假如你的ActivityAndroidManifest.xml文件里声明了处理android.nfc.action.TECH_DISCOVERED intent ,你必须建立一个Xml格式的资源文件,并加上你的activity支持的technologiestech-list集合里。这样你的activity将被认做能处理这些tech-list的处理者,若是tag使用的technology属于你的定义的list里,你的Activity将接收此Intent。你能够用getTechList()来得到tag支持的technologies

例如:若是一个tag被检测到支持MifareClassic, NdefFormatable, NfcA,你的tech-list集合必须指定了其中的一项或者多项来保证你的Activity能处理此Intent

下面是一个资源文件例子,定义了全部的technologies. 你能够根据须要删掉不须要的项,将此文件以任意名字+.xml保存到<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集合是getTechList()返回的technologies集合的子集,那么你的Activity将被认为匹配了。这个还提供操做。下面的例子表示支持 NfcANDef的卡,或者支持NfcBNDef的卡:

<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 文件中, 指定这个tech-list资源文件的方法是在<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>

使用前台发布系统Using the foreground dispatch system

前台发布系统容许一个Activity 拦截一个tag Intent 得到最高优先级的处理,这种方式很容易使用和实现:

1.     添加下列代码到ActivityonCreate() 方法里

a.     建立一个 PendingIntent 对象, 这样Android系统就能在一个tag被检测到时定位到这个对象

PendingIntent pendingIntent = PendingIntent.getActivity(
    this, , new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), );

b.    Intent filters里声明你想要处理的Intent,一个tag被检测到时先检查前台发布系统,若是前台Activity符合Intent filter的要求,那么前台的Activity的将处理此Intent。若是不符合,前台发布系统将Intent转到Intent发布系统。若是指定了nullIntent filters,当任意tag被检测到时,你将收到TAG_DISCOVERED intent。所以请注意你应该只处理你想要的Intent

    IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        try {
            ndef.addDataType("*/*");    /* Handles all MIME based dispatches.
                                           You should specify only the ones that you need. */
        }
        catch (MalformedMimeTypeException e) {
            throw new RuntimeException("fail", e);
        }
        intentFiltersArray = new IntentFilter[] {
                ndef,
        };

c.     设置一个你程序要处理的Tag technologies的列表,调用Object.class.getName() 方法来得到你想要支持处理的technology类。


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

2.     覆盖下面的方法来打开或关闭前台发布系统。好比onPause()onResume()方法。必须在主线程里调用enableForegroundDispatch(Activity, PendingIntent, IntentFilter[], String[][]) 并且Activity在前台(能够在onResume()里调用来保证这点)。你也要覆盖onNewIntent回调来处理获得的NFC tag数据。

public void onPause() {
    super.onPause();
    mAdapter.disableForegroundDispatch(this);
}  

public void onResume() {
    super.onResume();
    mAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, techListsArray);
}

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

使用NFC tag上的数据

NFC tag上的数据是以字节存放,因此你能够将其转换成其余你想要的格式。当往tag写东西时,你必须以字节格式来写。Android提供API来帮助写符合NDEF标准的信息。使用此标准能保证你的数据在往tag写时能被全部Android NFC设备支持。然而,不少tag使用他们本身的标准来存储数据,这些标准也被Android支持。但你必须本身实现协议栈来读写这些tag。你能够在android.nfc.tech里找到全部支持的technologies,而且能够在TagTechnology接口里对technology有个了解。这一段是简单介绍在android系统里怎样使用NDEF 消息。这不意味着是一个完整的NDEF功能的介绍。但标出了主要须要注意和使用的东西。

为了方便使用NDEF消息,android提供NdefRecord NdefMessage来包装原始字节数据为NDEF消息。一个NdefMessage是保存个或多个NdefRecords的容器。每一个NdefRecord有本身的惟一类型名字格式,记录类型和ID来与其余记录区分开。你能够存储不一样类型的记录,不一样的长度到同一个 NdefMessageNFC tag容量的限制决定你的NdefMessage的大小。
那些支持NdefNdefFormatable技术的tag能够返回和接受NdefMessage对象为参数来进行读写操做。你须要建立你本身的逻辑来为其余在android.nfc.techtag技术实现读写字节的操做。

你能够从NFC Forum(http://www.nfc-forum.org/specs/)下载NDEF消息标准的技术文档,好比纯文本和智慧型海报. NFCDemo例子里声明了纯文本和智慧型海报的NDef 消息。

读一个NFC tag

当一个NFC tag靠近一个NFC设备,一个相应的Intent将在设备上被建立。而后通知合适的程序来处理此Intent
下面的方法处理TAG_DISCOVERED intent而且使用迭代器来得到包含在NDEF tag负载的数据

NdefMessage[] getNdefMessages(Intent intent) {
   
// Parse the intent
   
NdefMessage[] msgs = null;
   
String action = intent.getAction();
   
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)) {
       
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
       
if (rawMsgs != null) {
            msgs
= new NdefMessage[rawMsgs.length];
           
for (int i = ; i < rawMsgs.length; i++) {
                msgs
[i] = (NdefMessage) rawMsgs[i];
           
}
       
}
       
else {
       
// Unknown tag type
           
byte[] empty = new byte[] {};
           
NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN, empty, empty, empty);
           
NdefMessage msg = new NdefMessage(new NdefRecord[] {record});
            msgs
= new NdefMessage[] {msg};
       
}
   
}        
   
else {
       
Log.e(TAG, "Unknown intent " + intent);
        finish
();
   
}
   
return msgs;
}

请记住NFC设备读到的数据是byte类型,因此你可能须要将他转成其余格式来呈现给用户。NFCDemo例子展现了怎样用com.example.android.nfc.record中的类来解析NDEF消息,好比纯文本和智慧型海报。

NFC tag

NFC tag写东西涉及到构造一个NDEF 消息和使用与tag匹配的Tag技术。下面的代码展现怎样写一个简单的文本到NdefFormatable tag

NdefFormatable tag = NdefFormatable.get(t);
Locale locale = Locale.US;
final byte[] langBytes = locale.getLanguage().getBytes(Charsets.US_ASCII);
String text = "Tag, you're it!";
final byte[] textBytes = text.getBytes(Charsets.UTF_8);
final int utfBit = ;
final char status = (char) (utfBit + langBytes.length);
final byte[] data = Bytes.concat(new byte[] {(byte) status}, langBytes, textBytes);
NdefRecord record = NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[], data);
try {
   
NdefRecord[] records = {text};
   
NdefMessage message = new NdefMessage(records);
    tag
.connect();
    tag
.format(message);
}
catch (Exception e){
   
//do error handling
}

点对点的数据交换

前台推送技术支持简单点对点的数据交换,你能够用enableForegroundNdefPush(Activity, NdefMessage) 方法来打开此功能. 为了用这个功能:

·         推送数据的Activity必须是前台Activity

·         你必须将你要发送的数据封装到NdefMessage对象里。

·         接收推送数据的设备必须支持com.android.npp  NDEF推送协议,这个对于Android设备是可选的

假如你的Activity打开了前台推送功能而且位于前台,这时标准的Intent发布系统是禁止的。然而,若是你的Activity容许前台发布系统,那么此时检测tag的功能仍然是可用的,不过只适用于前台发布系统。

要打开前台推送:

1.     建立一个你要推送给其余NFC设备的包含NdefRecordsNdefMessage

2.     在你的Activity里实现onResume() onPause() 的回调来正确处理前台推送的生命周期。你必须在你的Activity位于前台并在主线程里调用enableForegroundNdefPush(Activity, NdefMessage) (能够在onResume()里调用来保证这点).

public void onResume() {
    super.onResume();
    if (mAdapter != null)
        mAdapter.enableForegroundNdefPush(this, myNdefMessage);
}
public void onPause() {
    super.onPause();
    if (mAdapter != null)
        mAdapter.disableForegroundNdefPush(this);
}

Activity位于前台,你能够靠近另一个NFC设备来推送数据。请参考例子ForegroundNdefPush来了解点对点数据交换。

相关文章
相关标签/搜索