浅谈Android开发中的NFC功能
目录
1.“NFC”的自我描述
1.1 NFC功能的基本概念
1.2 NFC功能的背景、特性及发展趋势
2.NFC的基础知识、基本原理
2.1 NFC的工作模式
2.2 实现NFC功能需要的基础知识
2.2.1 NDEF数据格式
2.2.2 Android对NFC的支持
2.2.3 Android Beam
2.2.4 NFC前台调度系统
2.2.5 NFC标签调度系统及标签解析过程
2.3 实现NFC功能代码的基本步骤
3.进行NFC程序开发实战
3.1项目结构
3.2项目源码
3.3实现效果
参考资料
摘要:本文章对Android开发中的NFC技术进行了比较系统的描述,旨在让对NFC无了解的人能够快速了解NFC功能的大体情况。
1.“NFC”的自我描述
1.1 NFC功能的基本概念
NFC功能的全称为 Near Field Communication 即近场通信技术。
NFC(近场通讯)是一系列短距离无线技术,一般需要4cm或者更短去初始化连接。NFC功能允许你在NFC tag和Android设备或者两个Android设备间共享小负载数据。NFC工作频率为13.65 兆赫兹,通信速率为106 kbit/秒到 848kbit/秒。
NFC提供了一种简单、触控式的解决方案,可以简单直观地交换信息、访问内容与服务。
1.2 NFC功能的背景、特性及发展趋势
背景:NFC由非接触式射频识别(RFID)及互联互通技术整合演变而来,在单一芯片上结合感应式读卡器、感应式卡片和点对点的功能,能在短距离内与兼容设备进行识别和数据交换。这项技术最初只是RFID技术和网络技术的简单合并,现在已经演变成一种短距离无线通信技术,发展态势迅速。
特性:与RFID一样,NFC信息也是通过频谱中无线频率部分的电磁感应耦合方式传递,但两者之间还是存在很大的区别。NFC是一种提供轻松、安全、迅速的通信的无线连接技术,其传输范围比RFID小,RFID的传输范围可以达到几米、甚至几十米,但由于NFC采取了独特的信号衰减技术,相对于RFID来说NFC具有距离近、带宽高、能耗低等特点,此外,NFC具有与现有非接触智能卡技术兼容的特点,从应用前景看NFC目前来看更多的是针对于消费类电子设备相互通讯,有源RFID则更擅长在长距离识别。NFC与其它通信技术的比较如下:
通信技术比较
因为NFC功能具有直观性强、操作简单、成本低、建立连接速度更快等优点,同时也存在与蓝牙等常用通信工具相比使用距离短与传输速率低等缺点的原因,所以使得NFC功能在某些特定的领域具有强大的应用空间。
发展趋势:随着人民生活水平与社会发展速度的不断提高,以及人们对手机的应用越来越广泛,通过将智能卡嵌入到手机中实现NFC技术和手机的结合,使得NFC技术能广泛应用于一些日常的生活中去,大大方便了人民的日常生活。目前NFC的发展趋势已应用在许多领域之上,如:公交出行、门禁、移动支付、设备连接等方面。所以研究NFC技术具有一定的实用意义与重要性。
2.NFC的基础知识、基本原理
2.1 NFC的工作模式
由于NFC通信总是由一个发起者和一个接收者组成,发起者会主动发送电磁场,可以为被动接收者提供电源,其基本原理和收音机类似。正是由于被动式接收者可以通过发起者提供电源,因此接收者可以有非常简单的形式。NFC功能的工作模式可概括为三种:
第一种,读卡器模式。 该模式的本质为通过支持NFC的电子设备从带有NFC芯片的标签、物品等媒介中读写信息。NFC标签工作原理为:其不需要外部供电,当支持NFC的设备向标签读写数据时,NFC标签会发送某种磁场,该磁场会主动向NFC标签供电,从而顺利完成读写工作。
第二种,点对点模式。 即如上述对NFC功能与其它通信技术的比较图来看,该模式是用于不同NFC设备之间进行数据交换,其有效距离一般不能超过4厘米,传输建立速度与传输速率比红外和蓝牙技术快很多。该模式下NFC进行传输时,通常还会使用到androidBeam技术进行传输数据,当使用androidBeam传输数据的两部设备不再限于4厘米之内。
第三种,仿真卡模式。 其本质为将支持NFC功能的电子设备,如NFC手机,当作借书卡、公交卡、银行卡、门禁卡等IC卡使用。其实现的基本原理是将IC卡中信息凭证封装成数据包并存储在支持NFC的设备中。此外除了支持NFC的设备,刷电子设备处还需要NFC射频器,通过接收NFC射频器发送的信号与一系列验证之后,电子设备将IC卡中相应信息传入射频器中,最终从射频器传输到射频器所连接的电脑终端,完成相应处理操作。
2.2 实现NFC功能需要的基础知识
在描述NFC功能的实现时,需要掌了解一些基础的知识点,例如:NDEF数据格式及相关内容、NFC标签调度系统、NFC标签映射的实现、Android Beam等。
2.2.1 NDEF数据格式
需要了解NDEF数据格式的原因是因为,进行NFC操作时用的是NDEF消息格式来发送和接收NFC数据,是NFC数据交换格式,NFC组织约定的NFC tag中的数据格式。NEDF全称为NFC Data Exchange Format 是轻量级的紧凑的二进制格式,可带有URL、vCard和NFC定义的各种数据类型。
判断数据是否为NDEF格式:需同时满足两点1. TNF(类型名格式,Type Name Format)必须是NdefRecord.TNF_WELL_KNOWN。2. 可变的长度类型必须是NdefRecord.RTD_TEXT。
NDEF消息:在进行nfc数据传输时,NDEF数据被封装在一个消息中,该消息中包含了一条或多条记录。每个NDEF记录必须具有良好的你想要创建的记录类型的规范格式。此外各个记录由报头和有效载荷组成,其中NDEF记录的数据类型和大小由记录载荷的报头注明,这里的报头包含3部分,分别为Length、Type和Identifier。
Android 支持的NEDF数据操作:不同的NFC标签之间差异很大,有的只支持简单的读写操作,有的可以支持许许多多的复杂操作,而总得来说Android支持NEDF类型的数据进行的操作有 以下三点:
1.从NFC标签读取NDEF格式的数据。
2.向NFC标签写入NDEF格式的数据。
3.通过Android Beam技术将NDEF数据发送到另一部NFC设备。
非NDEF数据的操作:若想支持其他的不包含NDEF数据类型的标签,要存任意的数据,可以自行定义格式,编写自己的跟该标签通信的协议栈。这些数据格式本质也是普通的字节流,其数据含义可由开发人员自行定义。
接收到的nfc消息具有多条NDEF记录,其中第一条记录包含以下字段信息:
1.3-bit TNF(类型名称格式) 指示如何解释可变长度类型字段,在下表1中介绍有效值。
2.可变长度类型 说明记录的类型,如果使用TNF_WELL_KNOWN,那么则使用这个字段来指定记录的类型定义(RTD)。在下表2中定义了有效的RTD值。
3.可变长度ID 唯一标识该记录。这个字段不经常使用,但是,如果需要唯一的标识一个标记,那么就可以为该字段创建一个ID。
4.可变长度负载 你想读/写的实际的数据负载。一个NDEF消息能够包含多个NDEF记录,因此不要以为在NDEF消息的第一条NDEF记录中包含了所有的负载。
2.2.2 Android对NFC的支持
Android对NFC的支持主要在 android.nfc 和android.nfc.tech 两个包中。
android.nfc 包中主要类如下:
· NfcManager 用于管理Android设备中指出的所有NFC Adapter,因为大多安卓设备只支持一个NFC Adapter的原因,所有在这种情况下可以直接使用getDefaultAapater 获取系统支持的Adapter。
· NfcAdapter 为一个NFC Adapter 对象,用于定义一个Intent使系统在检测到NFC Tag时通知你定义的Activity,并提供用来注册forground tag 消息发送的方法等。
· NdefMessage 和NdefRecord NDEF 为NFC forum 定义的数据格式。
NdefMessage:描述NDEF格式的信息,实际上我们写入NFC标签的就是NdefMessage对象。
NdefRecord:描述NDEF信息的一个信息段,一个NdefMessage可能包含一个或者多个NdefRecord。
NdefMessage和NdefRecord是Android NFC技术的核心类,无论读写NDEF格式的NFC标签,还是通过Android Beam技术传递Ndef格式的数据,都需要这两个类。
Tag 代表一个被动式Tag对象,可以代表一个标签,卡片,钥匙扣等。当Android设备检测到一个Tag时,会创建一个Tag对象,将其放在Intent对象,然后发送到相应的Activity。
android.nfc.tech 包中则定义了可以对Tag进行的读写操作的类,这些类按照其使用的技术类型可以分成不同的类如:NfcA, NfcB, NfcF,以及MifareClassic 等。
android.nfc包中主要类及接口截图:
nfc
android.nfc,tech包中主要类及接口截图:
nfc.tech
2.2.3 Android Beam
在Android 中将NDEF数据从一台设备发送到另一部NFC设备的功能的实现是通过Android Beam的技术来实现的。Android Beam是一个基于近场通信所做的新功能,是一款应用程序,旨在最大程度地利用NFC技术,可让用户对几乎任何东西进行分享,无论是联系人、图片、网页链接还是YouTube链接。
Android Beam 功能允许设备把一个NDEF消息推送到物理/硬件上相互监听的另一个设备上。因为这种交互提供了比其他无线技术更容易的发送数据的方法,所以NFC不需要手动的设备发现或配对要求,两个设备在接近到一定范围时会自动的连接。Android Beam通过一组NFC API来使用,以便应用程序能够在设备之间来传输信息。
2.2.4 NFC前台调度系统
主要是一种用于在运行的程序中,处理NFC tag的技术,使得当前Activity能直接响应NFC标签,而不需要用户在选择所有能处理的Activity,之所以要使用到此系统的原因,就是因为当android设备扫描到一个NFC tag,通用的行为是自动找最合适的Activity会处理这个tag Intent而不需要用户来选择哪个Activity来处理。因为设备扫描NFC tags是在很短的范围和时间,如果让用户选择的话,那就有可能需要移动设备,这样将会打断这个扫描过程,从而中断该连接。
在实现当前Activity能直接响应NFC标签这个功能中使用到了tag分发系统,其包括了Intent发布系统与前台Activity发布系统,帮助正确的识别一个NFC tag是否是你的Activity想要处理的。对于前台Activity发布系统与Intent发布系统各自的作用为:
前台发布系统允许一个Activity覆盖掉Intent发布系统而首先处理此tag Intent,这要求你将要处理Tag Intent的Activity运行在前台,这样当一个NFC tag被扫描到,系统先检测前台的Activity是否支持处理此Intent,如果支持,即将此Intent传给此Activity,如果不支持,则转到Intent发布系统。
Intent发布系统检查所有Activities的intent filters,找出那些定义了可以处理此tag的Activity,如果有多个Activity都配置了处理同一个tag Intent,那么将使用Activity选择器来让用户选择使用哪个Activity。用户选择之后,将使用选择的Activity来处理此Intent.
2.2.5 NFC标签调度系统及标签解析过程
NFC标签调度系统用于分析扫描到的NFC标签,通过解析数据,在被扫描到的数据中尝试找到最适合的应用程序。
当系统检测到一个NFC标签的时候,会自动去寻找最合适的activity去处理这个intent.而此Intent定义了三种action:ACTION_NDEF_DISCOVERED、ACTION_TECH_DISCOVERED、ACTION_NDEF_DISCOVERED,三种action具体为:
ACTION_NDEF_DISCOVERED:当系统检测到tag中含有NDEF格式的数据时,且系统中有activity声明可以接受包含NDEF数据的Intent的时候,系统会优先发出这个action的intent。
ACTION_TECH_DISCOVERED:当没有任何一个activity声明自己可以响应ACTION_NDEF_DISCOVERED时,系统会尝试发出TECH的intent.即便tag中所包含的数据是NDEF的,但如果这个数据的MIME type或URI不能和任何一个activity所声明的吻合,系统也一样会尝试发出tech格式的intent,而不是NDEF.
ACTION_TAG_DISCOVERED:当系统发现前两个intent在系统中无人会接受的时,会用一个标签技术信息相关的默认Tag对象来代替,发送此默认的TAG类型的。
NFC标签调度系统对NFC标签进行解析的过程为:
1. 对接收到的NFC标签数据进行解析,搞清楚标签中标识数据负载的MIME类型或URI等信息。
2. 将MIME类型或URI等数据以及数据负载封装到一个Intent中。
3. 基于Intent来启动Activity,将Intent对象发送给感兴趣的应用程序(以下几点为对第三点完成过程的具体阐述)。
4. 用解析NFC标签时由标签调度系统创建的Intent对象(ACTION_NDEF_DISCOVERED或ACTION_TECH_DISCOVERED)来尝试启动Activity;
5. 如果没有对应的处理Intent的Activity,那么就会尝试使用下一个优先级的Intent(ACTION_TECH_DISCOVERED或ACTION_TAG_DISCOVERED)来启动Activity,直到有对应的应用程序来处理这个Intent,或者是直到标签调度系统尝试了所有可能的Intent。
6. 如果没有应用程序来处理任何类型的Intent,那么就不做任何事情。
下图为标签调度的流程:
标签调度流程
而NFC标签过滤有四种即使用上述提过知识点进行:1.过滤ACTION_NDEF_DISCOVERED 。2.过滤ACTION_TECH_DISCOVERED 。3.过滤ACTION_TAG_DISCOVERED 。4.nfc标签前台调度系统。各种方法的具体实现可去查看下方的参考博客链接。
2.3 实现NFC功能代码的基本步骤
进行支持NFC程序的开发时的基本步骤为:
1. 在AndroidManifest.xml中进行权限声明以及添加intent-filter过滤器进行支持。
进行权限声明:
<!--允许开发nfc的权限-->
<uses-permission android:name="android.permission.NFC"/>
<!--声明只有带有nfc功能的手机才能下载你在google市场发布的具有NFC功能的app-->
<uses-feature android:name="android.hardware.nfc" android:required="true" />
<!--声明支持的最小的Android Version 为10-->
<uses-sdk android:minSdkVersion="10"/>
1
2
3
4
5
6
进行intent-filter过滤器声明(以NDEF类型为例):
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<!--定义数据类型为纯文本类型,可根据自己需要自行定义-->
<data android:mimeType="text/plain" />
</intent-filter>
1
2
3
4
5
6
2. 进行定义可接收Tag的Activity,配置一下launchMode属性在AndroidManifest.xml中,例:
<activity android:name=".Example"
android:launchMode="singleTop"
android:label="自动打开通讯录"></activity>
1
2
3
3. 进行NFCAdapter的获取
private NfcAdapter mNfcAdapter =null;//1.声明一个nfc的Adapter
//2.检测NFC的检测函数
private void NfcCheck() {
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);//3.获取nfc适配器
if (mNfcAdapter == null) {
return; //3.如果获取的mNfcAdapter=null,则说明该手机不支持nfc功能
} else {
if (!mNfcAdapter.isEnabled()) {//4.如果手机有nfc功能,进一步判断nfc是否打开
Intent setNfc = new Intent(Settings.ACTION_NFC_SETTINGS);
startActivity(setNfc);//5.假如手机的nfc功能没有被打开。则跳到打开nfc功能的界面
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
4. 进行相关NFC功能操作的编写,实现具体操作,以及相关代码的编写,完成程序编写。
3.进行NFC程序开发实战
进行支持NFC程序的应用进行实战开发,本次编写的代码为对参考资料6中作者代码的借鉴,在其基础上进行修改、简化完成的。
3.1项目结构
项目结构的大致截图如下:
在这里插入图片描述
3.2项目源码
阅读源码时,请注意查看相应注释。
AndroidManifest.xml:为应用程序的资源配置文件,在其中定义了nfc功能需要的相关权限与实现NFC的功能类相关定义,相关代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.suxianpeng.blog_nfc">
<!--允许开发nfc的权限-->
<uses-permission android:name="android.permission.NFC"/>
<!--声明只有带有nfc功能的手机才能下载你在google市场发布的具有NFC功能的app-->
<uses-feature android:name="android.hardware.nfc" android:required="true" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--launchMode设置为singleTop或singelTask,保证Activity的重用唯一-->
<activity android:name=".NFC_AutoSearch_url"
android:launchMode="singleTop"
android:label="自动打开百度页面">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
MainActivity类:为系统的主类,界面入口处,通过自定义数组与数组适配器在activity_main.xml布局文件中实现了列表视图,通过switch语句使得在主界面可以实现自定义数组中所具有的操作,并且在该类的Oncreate方法中进行了NFCAdapter的获取与判断设备是否支持NFC功能的实现。具体代码为:
package com.suxianpeng.blog_nfc;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends NfcBase {
private TextView ifo_NFC;
private static final String[] strs = new String[]{
"自动打开百度页面",
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ifo_NFC = (TextView) findViewById(R.id.ifo_NFC);
// NFC适配器,所有的关于NFC的操作从该适配器进行
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (!ifNFCUse()) {
return;
}
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strs));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
switchActivity(position);
}
});
}
private void switchActivity(int position) {
switch (position) {
case 0: //自动打开百度页面
startActivity(new Intent(this, NFC_AutoSearch_url.class));
break;
default:
break;
}
}
/*
* 检测工作,判断设备的NFC支持情况
*/
protected Boolean ifNFCUse() {
if (mNfcAdapter == null) {
ifo_NFC.setText("设备不支持NFC!");
return false;
}
if (mNfcAdapter != null && !mNfcAdapter.isEnabled()) {
ifo_NFC.setText("请在系统设置中先启用NFC功能!");
return false;
}
return true;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
NfcBase类 :为进行NFC相关操作的基础类,为其它进行NFC操作的类服务,其它类需继承它。具体代码为:
package com.suxianpeng.blog_nfc;
import android.app.PendingIntent;
import android.content.Intent;
import android.nfc.NfcAdapter;
import androidx.appcompat.app.AppCompatActivity;
public class NfcBase extends AppCompatActivity {
protected NfcAdapter mNfcAdapter;
private PendingIntent mPendingIntent;
/**
* onCreat->onStart->onResume->onPause->onStop->onDestroy
* 启动Activity,界面可见时.
*/
@Override
protected void onStart() {
super.onStart();
//此处adapter需要重新获取,否则无法获取message
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
//一旦截获NFC消息,就会通过PendingIntent调用窗口
mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0);
}
/**
* 获得焦点,按钮可以点击
*/
@Override
public void onResume() {
super.onResume();
//设置处理优于所有其他NFC的处理
if (mNfcAdapter != null)
mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
}
/**
* 暂停Activity,界面获取焦点,按钮可以点击
*/
@Override
public void onPause() {
super.onPause();
//恢复默认状态
if (mNfcAdapter != null)
mNfcAdapter.disableForegroundDispatch(this);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
NFC_AutoSearch_url类 :具体实现的功能为解析nfc数据tag,往nfc标签中写入数据即百度的链接并自动访问该网站,具体实现为:
package com.suxianpeng.blog_nfc;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.nfc.tech.NdefFormatable;
import android.os.Bundle;
import android.widget.Toast;
public class NFC_AutoSearch_url extends NfcBase {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nfc_url);
}
@SuppressLint("MissingSuperCall")
@Override
public void onNewIntent(Intent intent) {//在onNewIntent方法中进行NFC标签相关操作,执行intent传递过来的Tag数据
//1.获取Tag对象
super.onNewIntent(intent);
Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
writeNFCTag(detectedTag);
}
/**
* 往标签写数据的方法
*/
public void writeNFCTag(Tag tag) {
if (tag == null) {
return;
}
NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]{NdefRecord
.createUri(Uri.parse("http://www.baidu.com"))});
//转换成字节获得大小
int size = ndefMessage.toByteArray().length;
try {
//2.判断NFC标签的数据类型(通过Ndef.get方法)
Ndef ndef = Ndef.get(tag);
//判断是否为NDEF标签
if (ndef != null) {
ndef.connect();
//判断是否支持可写
if (!ndef.isWritable()) {
return;
}
//判断标签的容量是否够用
if (ndef.getMaxSize() < size) {
return;
}
//3.写入数据
ndef.writeNdefMessage(ndefMessage);
Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show();
} else {
//若标签为格式化按此步骤进行
NdefFormatable format = NdefFormatable.get(tag);//Ndef格式类
//判断是否获得了NdefFormatable对象,有一些标签是只读的或者不允许格式化的
if (format != null) {
//连接
format.connect();
//格式化并将信息写入标签
format.format(ndefMessage);
Toast.makeText(this, "写入成功",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "写入失败", Toast.LENGTH_SHORT).show();
}
}
} catch (Exception e) {
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
activity_main.xml布局类 :代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorBackground">
<TextView
android:id="@+id/ifo_NFC"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="该设备支持NFC,请写入数据!" />
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
activity_nfc_url.xml布局类 :具体代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorBackground">
<TextView
android:id="@+id/ifo_NFC"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="该设备支持NFC,请写入数据!" />
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3.3实现效果
因为无法在虚拟机上运行所以就将程序导出为apk,在手机是进行运行,但是由于未事先购买nfc标签,导致也无法在手机在进行效果实验。但最终结果想来是正确的(待有nfc标签时,会进行验证并更新博客),在手机上运行的截图如下:
应用主界面:
主界面
NFC感应界面截图:
感应界面
该程序工程已上传到个人github网址中:https://github.com/SuXianPeng/Project-NFC/tree/master
小结
本篇博客比较系统的对NFC功能进行了描述,其中也参考了许多高手的博客,通过此次博客对NFC功能的原理与实现有了比较明晰、清楚的了解。博客就先写到这,如果有那些不足,或错误、需要改正之处,欢迎指出。
参考资料
参考博客:https://www.jianshu.com/p/e89cc9bba8a6
参考博客:https://www.csdn.net/gather_22/MtTakg5sMTI3My1ibG9n.html
前台调度系统的具体实现步骤可见博客:https://www.cnblogs.com/H-BolinBlog/p/5378020.html
参考博客:https://www.cnblogs.com/mythou/p/3190390.html
参考博客:https://www.jianshu.com/p/cf36c214f2a8(有关NFC标签过滤的相关知识可查看此博客)
实现代码所参考的github项目:https://github.com/RickyYu/Nfc-Android(与1.参考博客的作者为同一人)
作者:苏显鹏
原文链接:https://blog.csdn.net/qq_41522183/article/details/106724201
————————————————
版权声明:本文为CSDN博主「fjnu_se」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/fjnu_se/article/details/106742813
1.“NFC”的自我描述
1.1 NFC功能的基本概念
1.2 NFC功能的背景、特性及发展趋势
2.NFC的基础知识、基本原理
2.1 NFC的工作模式
2.2 实现NFC功能需要的基础知识
2.2.1 NDEF数据格式
2.2.2 Android对NFC的支持
2.2.3 Android Beam
2.2.4 NFC前台调度系统
2.2.5 NFC标签调度系统及标签解析过程
2.3 实现NFC功能代码的基本步骤
3.进行NFC程序开发实战
3.1项目结构
3.2项目源码
3.3实现效果
参考资料
摘要:本文章对Android开发中的NFC技术进行了比较系统的描述,旨在让对NFC无了解的人能够快速了解NFC功能的大体情况。
1.“NFC”的自我描述
1.1 NFC功能的基本概念
NFC功能的全称为 Near Field Communication 即近场通信技术。
NFC(近场通讯)是一系列短距离无线技术,一般需要4cm或者更短去初始化连接。NFC功能允许你在NFC tag和Android设备或者两个Android设备间共享小负载数据。NFC工作频率为13.65 兆赫兹,通信速率为106 kbit/秒到 848kbit/秒。
NFC提供了一种简单、触控式的解决方案,可以简单直观地交换信息、访问内容与服务。
1.2 NFC功能的背景、特性及发展趋势
背景:NFC由非接触式射频识别(RFID)及互联互通技术整合演变而来,在单一芯片上结合感应式读卡器、感应式卡片和点对点的功能,能在短距离内与兼容设备进行识别和数据交换。这项技术最初只是RFID技术和网络技术的简单合并,现在已经演变成一种短距离无线通信技术,发展态势迅速。
特性:与RFID一样,NFC信息也是通过频谱中无线频率部分的电磁感应耦合方式传递,但两者之间还是存在很大的区别。NFC是一种提供轻松、安全、迅速的通信的无线连接技术,其传输范围比RFID小,RFID的传输范围可以达到几米、甚至几十米,但由于NFC采取了独特的信号衰减技术,相对于RFID来说NFC具有距离近、带宽高、能耗低等特点,此外,NFC具有与现有非接触智能卡技术兼容的特点,从应用前景看NFC目前来看更多的是针对于消费类电子设备相互通讯,有源RFID则更擅长在长距离识别。NFC与其它通信技术的比较如下:
通信技术比较
因为NFC功能具有直观性强、操作简单、成本低、建立连接速度更快等优点,同时也存在与蓝牙等常用通信工具相比使用距离短与传输速率低等缺点的原因,所以使得NFC功能在某些特定的领域具有强大的应用空间。
发展趋势:随着人民生活水平与社会发展速度的不断提高,以及人们对手机的应用越来越广泛,通过将智能卡嵌入到手机中实现NFC技术和手机的结合,使得NFC技术能广泛应用于一些日常的生活中去,大大方便了人民的日常生活。目前NFC的发展趋势已应用在许多领域之上,如:公交出行、门禁、移动支付、设备连接等方面。所以研究NFC技术具有一定的实用意义与重要性。
2.NFC的基础知识、基本原理
2.1 NFC的工作模式
由于NFC通信总是由一个发起者和一个接收者组成,发起者会主动发送电磁场,可以为被动接收者提供电源,其基本原理和收音机类似。正是由于被动式接收者可以通过发起者提供电源,因此接收者可以有非常简单的形式。NFC功能的工作模式可概括为三种:
第一种,读卡器模式。 该模式的本质为通过支持NFC的电子设备从带有NFC芯片的标签、物品等媒介中读写信息。NFC标签工作原理为:其不需要外部供电,当支持NFC的设备向标签读写数据时,NFC标签会发送某种磁场,该磁场会主动向NFC标签供电,从而顺利完成读写工作。
第二种,点对点模式。 即如上述对NFC功能与其它通信技术的比较图来看,该模式是用于不同NFC设备之间进行数据交换,其有效距离一般不能超过4厘米,传输建立速度与传输速率比红外和蓝牙技术快很多。该模式下NFC进行传输时,通常还会使用到androidBeam技术进行传输数据,当使用androidBeam传输数据的两部设备不再限于4厘米之内。
第三种,仿真卡模式。 其本质为将支持NFC功能的电子设备,如NFC手机,当作借书卡、公交卡、银行卡、门禁卡等IC卡使用。其实现的基本原理是将IC卡中信息凭证封装成数据包并存储在支持NFC的设备中。此外除了支持NFC的设备,刷电子设备处还需要NFC射频器,通过接收NFC射频器发送的信号与一系列验证之后,电子设备将IC卡中相应信息传入射频器中,最终从射频器传输到射频器所连接的电脑终端,完成相应处理操作。
2.2 实现NFC功能需要的基础知识
在描述NFC功能的实现时,需要掌了解一些基础的知识点,例如:NDEF数据格式及相关内容、NFC标签调度系统、NFC标签映射的实现、Android Beam等。
2.2.1 NDEF数据格式
需要了解NDEF数据格式的原因是因为,进行NFC操作时用的是NDEF消息格式来发送和接收NFC数据,是NFC数据交换格式,NFC组织约定的NFC tag中的数据格式。NEDF全称为NFC Data Exchange Format 是轻量级的紧凑的二进制格式,可带有URL、vCard和NFC定义的各种数据类型。
判断数据是否为NDEF格式:需同时满足两点1. TNF(类型名格式,Type Name Format)必须是NdefRecord.TNF_WELL_KNOWN。2. 可变的长度类型必须是NdefRecord.RTD_TEXT。
NDEF消息:在进行nfc数据传输时,NDEF数据被封装在一个消息中,该消息中包含了一条或多条记录。每个NDEF记录必须具有良好的你想要创建的记录类型的规范格式。此外各个记录由报头和有效载荷组成,其中NDEF记录的数据类型和大小由记录载荷的报头注明,这里的报头包含3部分,分别为Length、Type和Identifier。
Android 支持的NEDF数据操作:不同的NFC标签之间差异很大,有的只支持简单的读写操作,有的可以支持许许多多的复杂操作,而总得来说Android支持NEDF类型的数据进行的操作有 以下三点:
1.从NFC标签读取NDEF格式的数据。
2.向NFC标签写入NDEF格式的数据。
3.通过Android Beam技术将NDEF数据发送到另一部NFC设备。
非NDEF数据的操作:若想支持其他的不包含NDEF数据类型的标签,要存任意的数据,可以自行定义格式,编写自己的跟该标签通信的协议栈。这些数据格式本质也是普通的字节流,其数据含义可由开发人员自行定义。
接收到的nfc消息具有多条NDEF记录,其中第一条记录包含以下字段信息:
1.3-bit TNF(类型名称格式) 指示如何解释可变长度类型字段,在下表1中介绍有效值。
2.可变长度类型 说明记录的类型,如果使用TNF_WELL_KNOWN,那么则使用这个字段来指定记录的类型定义(RTD)。在下表2中定义了有效的RTD值。
3.可变长度ID 唯一标识该记录。这个字段不经常使用,但是,如果需要唯一的标识一个标记,那么就可以为该字段创建一个ID。
4.可变长度负载 你想读/写的实际的数据负载。一个NDEF消息能够包含多个NDEF记录,因此不要以为在NDEF消息的第一条NDEF记录中包含了所有的负载。
2.2.2 Android对NFC的支持
Android对NFC的支持主要在 android.nfc 和android.nfc.tech 两个包中。
android.nfc 包中主要类如下:
· NfcManager 用于管理Android设备中指出的所有NFC Adapter,因为大多安卓设备只支持一个NFC Adapter的原因,所有在这种情况下可以直接使用getDefaultAapater 获取系统支持的Adapter。
· NfcAdapter 为一个NFC Adapter 对象,用于定义一个Intent使系统在检测到NFC Tag时通知你定义的Activity,并提供用来注册forground tag 消息发送的方法等。
· NdefMessage 和NdefRecord NDEF 为NFC forum 定义的数据格式。
NdefMessage:描述NDEF格式的信息,实际上我们写入NFC标签的就是NdefMessage对象。
NdefRecord:描述NDEF信息的一个信息段,一个NdefMessage可能包含一个或者多个NdefRecord。
NdefMessage和NdefRecord是Android NFC技术的核心类,无论读写NDEF格式的NFC标签,还是通过Android Beam技术传递Ndef格式的数据,都需要这两个类。
Tag 代表一个被动式Tag对象,可以代表一个标签,卡片,钥匙扣等。当Android设备检测到一个Tag时,会创建一个Tag对象,将其放在Intent对象,然后发送到相应的Activity。
android.nfc.tech 包中则定义了可以对Tag进行的读写操作的类,这些类按照其使用的技术类型可以分成不同的类如:NfcA, NfcB, NfcF,以及MifareClassic 等。
android.nfc包中主要类及接口截图:
nfc
android.nfc,tech包中主要类及接口截图:
nfc.tech
2.2.3 Android Beam
在Android 中将NDEF数据从一台设备发送到另一部NFC设备的功能的实现是通过Android Beam的技术来实现的。Android Beam是一个基于近场通信所做的新功能,是一款应用程序,旨在最大程度地利用NFC技术,可让用户对几乎任何东西进行分享,无论是联系人、图片、网页链接还是YouTube链接。
Android Beam 功能允许设备把一个NDEF消息推送到物理/硬件上相互监听的另一个设备上。因为这种交互提供了比其他无线技术更容易的发送数据的方法,所以NFC不需要手动的设备发现或配对要求,两个设备在接近到一定范围时会自动的连接。Android Beam通过一组NFC API来使用,以便应用程序能够在设备之间来传输信息。
2.2.4 NFC前台调度系统
主要是一种用于在运行的程序中,处理NFC tag的技术,使得当前Activity能直接响应NFC标签,而不需要用户在选择所有能处理的Activity,之所以要使用到此系统的原因,就是因为当android设备扫描到一个NFC tag,通用的行为是自动找最合适的Activity会处理这个tag Intent而不需要用户来选择哪个Activity来处理。因为设备扫描NFC tags是在很短的范围和时间,如果让用户选择的话,那就有可能需要移动设备,这样将会打断这个扫描过程,从而中断该连接。
在实现当前Activity能直接响应NFC标签这个功能中使用到了tag分发系统,其包括了Intent发布系统与前台Activity发布系统,帮助正确的识别一个NFC tag是否是你的Activity想要处理的。对于前台Activity发布系统与Intent发布系统各自的作用为:
前台发布系统允许一个Activity覆盖掉Intent发布系统而首先处理此tag Intent,这要求你将要处理Tag Intent的Activity运行在前台,这样当一个NFC tag被扫描到,系统先检测前台的Activity是否支持处理此Intent,如果支持,即将此Intent传给此Activity,如果不支持,则转到Intent发布系统。
Intent发布系统检查所有Activities的intent filters,找出那些定义了可以处理此tag的Activity,如果有多个Activity都配置了处理同一个tag Intent,那么将使用Activity选择器来让用户选择使用哪个Activity。用户选择之后,将使用选择的Activity来处理此Intent.
2.2.5 NFC标签调度系统及标签解析过程
NFC标签调度系统用于分析扫描到的NFC标签,通过解析数据,在被扫描到的数据中尝试找到最适合的应用程序。
当系统检测到一个NFC标签的时候,会自动去寻找最合适的activity去处理这个intent.而此Intent定义了三种action:ACTION_NDEF_DISCOVERED、ACTION_TECH_DISCOVERED、ACTION_NDEF_DISCOVERED,三种action具体为:
ACTION_NDEF_DISCOVERED:当系统检测到tag中含有NDEF格式的数据时,且系统中有activity声明可以接受包含NDEF数据的Intent的时候,系统会优先发出这个action的intent。
ACTION_TECH_DISCOVERED:当没有任何一个activity声明自己可以响应ACTION_NDEF_DISCOVERED时,系统会尝试发出TECH的intent.即便tag中所包含的数据是NDEF的,但如果这个数据的MIME type或URI不能和任何一个activity所声明的吻合,系统也一样会尝试发出tech格式的intent,而不是NDEF.
ACTION_TAG_DISCOVERED:当系统发现前两个intent在系统中无人会接受的时,会用一个标签技术信息相关的默认Tag对象来代替,发送此默认的TAG类型的。
NFC标签调度系统对NFC标签进行解析的过程为:
1. 对接收到的NFC标签数据进行解析,搞清楚标签中标识数据负载的MIME类型或URI等信息。
2. 将MIME类型或URI等数据以及数据负载封装到一个Intent中。
3. 基于Intent来启动Activity,将Intent对象发送给感兴趣的应用程序(以下几点为对第三点完成过程的具体阐述)。
4. 用解析NFC标签时由标签调度系统创建的Intent对象(ACTION_NDEF_DISCOVERED或ACTION_TECH_DISCOVERED)来尝试启动Activity;
5. 如果没有对应的处理Intent的Activity,那么就会尝试使用下一个优先级的Intent(ACTION_TECH_DISCOVERED或ACTION_TAG_DISCOVERED)来启动Activity,直到有对应的应用程序来处理这个Intent,或者是直到标签调度系统尝试了所有可能的Intent。
6. 如果没有应用程序来处理任何类型的Intent,那么就不做任何事情。
下图为标签调度的流程:
标签调度流程
而NFC标签过滤有四种即使用上述提过知识点进行:1.过滤ACTION_NDEF_DISCOVERED 。2.过滤ACTION_TECH_DISCOVERED 。3.过滤ACTION_TAG_DISCOVERED 。4.nfc标签前台调度系统。各种方法的具体实现可去查看下方的参考博客链接。
2.3 实现NFC功能代码的基本步骤
进行支持NFC程序的开发时的基本步骤为:
1. 在AndroidManifest.xml中进行权限声明以及添加intent-filter过滤器进行支持。
进行权限声明:
<!--允许开发nfc的权限-->
<uses-permission android:name="android.permission.NFC"/>
<!--声明只有带有nfc功能的手机才能下载你在google市场发布的具有NFC功能的app-->
<uses-feature android:name="android.hardware.nfc" android:required="true" />
<!--声明支持的最小的Android Version 为10-->
<uses-sdk android:minSdkVersion="10"/>
1
2
3
4
5
6
进行intent-filter过滤器声明(以NDEF类型为例):
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<!--定义数据类型为纯文本类型,可根据自己需要自行定义-->
<data android:mimeType="text/plain" />
</intent-filter>
1
2
3
4
5
6
2. 进行定义可接收Tag的Activity,配置一下launchMode属性在AndroidManifest.xml中,例:
<activity android:name=".Example"
android:launchMode="singleTop"
android:label="自动打开通讯录"></activity>
1
2
3
3. 进行NFCAdapter的获取
private NfcAdapter mNfcAdapter =null;//1.声明一个nfc的Adapter
//2.检测NFC的检测函数
private void NfcCheck() {
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);//3.获取nfc适配器
if (mNfcAdapter == null) {
return; //3.如果获取的mNfcAdapter=null,则说明该手机不支持nfc功能
} else {
if (!mNfcAdapter.isEnabled()) {//4.如果手机有nfc功能,进一步判断nfc是否打开
Intent setNfc = new Intent(Settings.ACTION_NFC_SETTINGS);
startActivity(setNfc);//5.假如手机的nfc功能没有被打开。则跳到打开nfc功能的界面
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
4. 进行相关NFC功能操作的编写,实现具体操作,以及相关代码的编写,完成程序编写。
3.进行NFC程序开发实战
进行支持NFC程序的应用进行实战开发,本次编写的代码为对参考资料6中作者代码的借鉴,在其基础上进行修改、简化完成的。
3.1项目结构
项目结构的大致截图如下:
在这里插入图片描述
3.2项目源码
阅读源码时,请注意查看相应注释。
AndroidManifest.xml:为应用程序的资源配置文件,在其中定义了nfc功能需要的相关权限与实现NFC的功能类相关定义,相关代码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.suxianpeng.blog_nfc">
<!--允许开发nfc的权限-->
<uses-permission android:name="android.permission.NFC"/>
<!--声明只有带有nfc功能的手机才能下载你在google市场发布的具有NFC功能的app-->
<uses-feature android:name="android.hardware.nfc" android:required="true" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--launchMode设置为singleTop或singelTask,保证Activity的重用唯一-->
<activity android:name=".NFC_AutoSearch_url"
android:launchMode="singleTop"
android:label="自动打开百度页面">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
MainActivity类:为系统的主类,界面入口处,通过自定义数组与数组适配器在activity_main.xml布局文件中实现了列表视图,通过switch语句使得在主界面可以实现自定义数组中所具有的操作,并且在该类的Oncreate方法中进行了NFCAdapter的获取与判断设备是否支持NFC功能的实现。具体代码为:
package com.suxianpeng.blog_nfc;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends NfcBase {
private TextView ifo_NFC;
private static final String[] strs = new String[]{
"自动打开百度页面",
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ifo_NFC = (TextView) findViewById(R.id.ifo_NFC);
// NFC适配器,所有的关于NFC的操作从该适配器进行
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (!ifNFCUse()) {
return;
}
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, strs));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
switchActivity(position);
}
});
}
private void switchActivity(int position) {
switch (position) {
case 0: //自动打开百度页面
startActivity(new Intent(this, NFC_AutoSearch_url.class));
break;
default:
break;
}
}
/*
* 检测工作,判断设备的NFC支持情况
*/
protected Boolean ifNFCUse() {
if (mNfcAdapter == null) {
ifo_NFC.setText("设备不支持NFC!");
return false;
}
if (mNfcAdapter != null && !mNfcAdapter.isEnabled()) {
ifo_NFC.setText("请在系统设置中先启用NFC功能!");
return false;
}
return true;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
NfcBase类 :为进行NFC相关操作的基础类,为其它进行NFC操作的类服务,其它类需继承它。具体代码为:
package com.suxianpeng.blog_nfc;
import android.app.PendingIntent;
import android.content.Intent;
import android.nfc.NfcAdapter;
import androidx.appcompat.app.AppCompatActivity;
public class NfcBase extends AppCompatActivity {
protected NfcAdapter mNfcAdapter;
private PendingIntent mPendingIntent;
/**
* onCreat->onStart->onResume->onPause->onStop->onDestroy
* 启动Activity,界面可见时.
*/
@Override
protected void onStart() {
super.onStart();
//此处adapter需要重新获取,否则无法获取message
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
//一旦截获NFC消息,就会通过PendingIntent调用窗口
mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0);
}
/**
* 获得焦点,按钮可以点击
*/
@Override
public void onResume() {
super.onResume();
//设置处理优于所有其他NFC的处理
if (mNfcAdapter != null)
mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
}
/**
* 暂停Activity,界面获取焦点,按钮可以点击
*/
@Override
public void onPause() {
super.onPause();
//恢复默认状态
if (mNfcAdapter != null)
mNfcAdapter.disableForegroundDispatch(this);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
NFC_AutoSearch_url类 :具体实现的功能为解析nfc数据tag,往nfc标签中写入数据即百度的链接并自动访问该网站,具体实现为:
package com.suxianpeng.blog_nfc;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.nfc.tech.NdefFormatable;
import android.os.Bundle;
import android.widget.Toast;
public class NFC_AutoSearch_url extends NfcBase {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_nfc_url);
}
@SuppressLint("MissingSuperCall")
@Override
public void onNewIntent(Intent intent) {//在onNewIntent方法中进行NFC标签相关操作,执行intent传递过来的Tag数据
//1.获取Tag对象
super.onNewIntent(intent);
Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
writeNFCTag(detectedTag);
}
/**
* 往标签写数据的方法
*/
public void writeNFCTag(Tag tag) {
if (tag == null) {
return;
}
NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]{NdefRecord
.createUri(Uri.parse("http://www.baidu.com"))});
//转换成字节获得大小
int size = ndefMessage.toByteArray().length;
try {
//2.判断NFC标签的数据类型(通过Ndef.get方法)
Ndef ndef = Ndef.get(tag);
//判断是否为NDEF标签
if (ndef != null) {
ndef.connect();
//判断是否支持可写
if (!ndef.isWritable()) {
return;
}
//判断标签的容量是否够用
if (ndef.getMaxSize() < size) {
return;
}
//3.写入数据
ndef.writeNdefMessage(ndefMessage);
Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show();
} else {
//若标签为格式化按此步骤进行
NdefFormatable format = NdefFormatable.get(tag);//Ndef格式类
//判断是否获得了NdefFormatable对象,有一些标签是只读的或者不允许格式化的
if (format != null) {
//连接
format.connect();
//格式化并将信息写入标签
format.format(ndefMessage);
Toast.makeText(this, "写入成功",
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "写入失败", Toast.LENGTH_SHORT).show();
}
}
} catch (Exception e) {
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
activity_main.xml布局类 :代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorBackground">
<TextView
android:id="@+id/ifo_NFC"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="该设备支持NFC,请写入数据!" />
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
activity_nfc_url.xml布局类 :具体代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="@color/colorBackground">
<TextView
android:id="@+id/ifo_NFC"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="该设备支持NFC,请写入数据!" />
<ListView
android:id="@+id/listview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3.3实现效果
因为无法在虚拟机上运行所以就将程序导出为apk,在手机是进行运行,但是由于未事先购买nfc标签,导致也无法在手机在进行效果实验。但最终结果想来是正确的(待有nfc标签时,会进行验证并更新博客),在手机上运行的截图如下:
应用主界面:
主界面
NFC感应界面截图:
感应界面
该程序工程已上传到个人github网址中:https://github.com/SuXianPeng/Project-NFC/tree/master
小结
本篇博客比较系统的对NFC功能进行了描述,其中也参考了许多高手的博客,通过此次博客对NFC功能的原理与实现有了比较明晰、清楚的了解。博客就先写到这,如果有那些不足,或错误、需要改正之处,欢迎指出。
参考资料
参考博客:https://www.jianshu.com/p/e89cc9bba8a6
参考博客:https://www.csdn.net/gather_22/MtTakg5sMTI3My1ibG9n.html
前台调度系统的具体实现步骤可见博客:https://www.cnblogs.com/H-BolinBlog/p/5378020.html
参考博客:https://www.cnblogs.com/mythou/p/3190390.html
参考博客:https://www.jianshu.com/p/cf36c214f2a8(有关NFC标签过滤的相关知识可查看此博客)
实现代码所参考的github项目:https://github.com/RickyYu/Nfc-Android(与1.参考博客的作者为同一人)
作者:苏显鹏
原文链接:https://blog.csdn.net/qq_41522183/article/details/106724201
————————————————
版权声明:本文为CSDN博主「fjnu_se」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/fjnu_se/article/details/106742813