在安卓开发中开始应用NFC
NFC (近场通信)。
NFC 科技代表近场通信,你可以在 NFC 论坛上找到 NFC 的详细信息。在本文中,我们将分析 NFC 的一些基础知识,并且我们还将描述如何在安卓系统中实现一个利用 NFC 的 APP(应用程序)。
如果你想做 NFC 实验,那么你在几个网站上花费几欧元就能买到 NFC 。
NFC 可以用于不同的情景:在家中时,我们可以使用它来打开 WiFi 或者执行一些任务操作等等。
本文中,我们将注意力集中在 NDEF 数据,它是一种特殊类型的 NFC 标记。不过,在使用 NFC 之前,我们必须遵循一些基本步骤。
NFC 过滤器
当我们使用 NFC 标记时,我们要做的第一件事就是,当我们接近一个 NFC 标记的时候,我们的 APP 可以收到通知。为了实现这个目的,我们需要使用一个意图过滤器。安卓 SDK 中提供了三种不同的过滤器,我们可以以不同的优先级来使用它们:
ACTION_NDEF_DISCOVERED
ACTION_TECH_DISCOVERED
ACTION_TAG_DISCOVERED
我们重点关注 ACTION_NDEF_DISCOVERED,它拥有最高的优先级。正如前面所说的,我们的目的是,当智能手机接近一个 NFC 标记时能够收到通知,并且如果我们只安装了这一个 APP,并且它能够处理这个 NFC 标记,那么我们希望该 APP 能够立即开始处理。为了实现这一点,我们在 Manifest.xml 中注册过滤器:
package="com.survivingwithandroid.nfc">
....
在第 6 行,我们注册了 APP,以使得它可以收到 ACTION_NDEF_DISCOVERED 通知。我们使用不同类型的过滤器,在这个例子中(第 8 行)我们使用了 mine 类型。换句话说,当发现一个 NFC 标记 NDEF 并且它的 mine 类型为“text/plain”时,我们的 APP 将会启动。其实,我们可以使用几种 mine 类型来过滤,而不仅仅是 text/plain。此外,我们还能以协议或一个字符串模式来使用其他类型的过滤器(如 android:scheme)来过滤。
NFC 前台调度
如果我们的 APP 没处于前台,就会开始意图过滤。如果我们的应用程序运行在前台,那么当我们的智能手机移动到一个 NFC 标记时,它将不会收到通知。在这种情况下,我们必须使用一种称为NFC前台调度的技术。第一步是,在我们的代码中定义意图过滤器(正如我们在 Manifest.xml 中做的那样):
@Override
protectedvoidonCreate(Bundle savedInstanceState){
...
Intent nfcIntent=newIntent(this,getClass());
nfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
nfcPendingIntent=
PendingIntent.getActivity(this,0,nfcIntent,0);
IntentFilter tagIntentFilter=
newIntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try{
tagIntentFilter.addDataType("text/plain");
intentFiltersArray=newIntentFilter[]{tagIntentFilter};
}
catch(Throwablet){
t.printStackTrace();
}
}
现在,我们必须注册我们的过滤器,在 onResume 方法中以这种方式实现它:
protectedvoidonResume(){
super.onResume();
nfcAdpt.enableForegroundDispatch(
this,
nfcPendingIntent,
intentFiltersArray,
null);
handleIntent(getIntent());
}
此外,也应该记住,只要 APP 退回到后台,我们就应该关闭前台调度,而要实现这一点,最好的地方是在 onPause 方法中。
@Override
protectedvoidonPause(){
super.onPause();
nfcAdpt.disableForegroundDispatch(this);
}
其中,nfcAdpt 是 NFC 适配器。
使用 NFCAdapter 处理 NFC
一旦我们创建了过滤器,我们必须与智能手机中的 NFC 组件交互。为此,我们使用安卓 SDK 提供的 NfcAdapter。使用这个类,我们能够检测智能手机是否支持 NFC,或者 NFC 功能是否开启或关闭。
@Override
protectedvoidonCreate(Bundle savedInstanceState){
...
nfcAdpt=NfcAdapter.getDefaultAdapter(this);
// Check if the smartphone has NFC
if(nfcAdpt==null){
Toast.makeText(this,"NFC not supported",Toast.LENGTH_LONG).show();
finish();
}
// Check if NFC is enabled
if(!nfcAdpt.isEnabled()){
Toast.makeText(this,"Enable NFC before using the app",Toast.LENGTH_LONG).show();
}
}
NFC 数据:负载
既然我们知道了如何处理 NFC 标记,接着我们就想读取标记内容。在 NFC 说明文档中,定义了几种类型的内容:
NFC Forum well-known type
Media-type
Absolute URI
NFC Forum external type
每种类型都有它自己的有效负载。一般来说,一个 NFC NDEF 数据由一条信息组成,一条信息可以包含一个或多个记录,每个记录由一个头和一个负载(真正的信息)组成。现在,如果我们想读取 NFC NDEF 标记中的数据,我们可以使用下面的代码:
@Override
publicvoidonNewIntent(Intent intent){
Log.d("Nfc","New intent");
getTag(intent);
}
privatevoidgetTag(Intenti){
if(i==null)
return;
Stringtype=i.getType();
Stringaction=i.getAction();
List dataList=newArrayList();
if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)){
Log.d("Nfc","Action NDEF Found");
Parcelable[]parcs=i.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
for(Parcelablep:parcs){
recNumberTxt.setText(String.valueOf(numRec));
NdefRecord[]records=msg.getRecords();
for(NdefRecord record:records){
shorttnf=record.getTnf();
// Here we handle the payload
}
}
}
}