文章整理总结java层,NFC读取和写入Tag的流程。
整体的时序图:
1、读取Tag的流程
NfcService启动完成后,会通过NfcService中的applyRouting方法设置对应的Discovery,也就是NCI的
2103的命令(此处不了解不影响后面),根据设置的命令参数来决定设备是处于listen模式,还是polling模式。
当处于polling模式下会检测那个Tag进入到了自己的射频厂,进而产生反应。与其相对的是listen模式,Tag
就相当于是listen模式,监听谁往外polling,产生响应.
下面先详细分析applyRouting。
参数force为true的时候,基本上就会执行一次enableDiscovery.
1
void applyRouting(boolean force) {
2
synchronized (this) {
3
......
4
//mInProvisionMode:用来标记当前系统是否处于开机向导界面.
5
//对应于android开机时候的引导provision apk,是否出在引导模式
6
if (mInProvisionMode) {
7
mInProvisionMode = Settings.Secure.getInt(mContentResolver,
8
Settings.Global.DEVICE_PROVISIONED, 0) == 0;
9
//当运行到这里的时候就代表,这是刷完系统,开机引导完,第一次走到这里,
10
//并且现在开机引导已经完毕,此时下面可能已经是false
11
if (!mInProvisionMode) {
12
//就是设置NfcDispatcher中的mProvisioningOnly = false;
13
mNfcDispatcher.disableProvisioningMode();
14
//调用native方法doSetProvisionMode,去通知native层,当前不是处于ProvisionMode
15
mDeviceHost.doSetProvisionMode(mInProvisionMode);
16
}
17
}
18
// 当此时正在和一个Tag在通信的时候,延迟re-configuration.
19
if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && isTagPresent()) {
20
Log.d(TAG, "Not updating discovery parameters, tag connected.");
21
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESUME_POLLING),
22
APPLY_ROUTING_RETRY_TIMEOUT_MS);
23
return;
24
}
25
try {
26
//此处更新于NFC RF的Discovery参数.
27
NfcDiscoveryParameters newParams = computeDiscoveryParameters(mScreenState);
28
//传入参数为true的时候或者参数有所变化.
29
if (force || !newParams.equals(mCurrentDiscoveryParameters)) {
30
//只要routingtable变过,或者有新的tech的改变。
31
if (newParams.shouldEnableDiscovery()) {
32
boolean shouldRestart =
33
mCurrentDiscoveryParameters.shouldEnableDiscovery();
34
//最重要的就是调用到了这里,mDeviceHost的实现类是NativeNfcManager
35
//最终调用到内部的如下:
36
// private native void doEnableDiscovery(int techMask,
37
// boolean enableLowPowerPolling,
38
// boolean enableReaderMode,
39
// boolean enableP2p,
40
// boolean restart);
41
//去native层,初始化RF的相关参数。
42
mDeviceHost.enableDiscovery(newParams, shouldRestart);
43
} else {
44
mDeviceHost.disableDiscovery();
45
}
46
mCurrentDiscoveryParameters = newParams;
47
} else {
48
Log.d(TAG, "Discovery configuration equal, not updating.");
49
}
50
} finally {
51
......
52
}
53
}
54
}
我们看一下computeDiscoveryParameters这个函数,它返回NfcDiscoveryParameters,这个类描述了
用于enable NFC的tag discovery、polling、host card emulation的各个参数,配置的不同最终初始化的NFC
功能不同.
1
//基于屏幕的状态重新计算NfcDiscoveryParameters.
2
private NfcDiscoveryParameters computeDiscoveryParameters(int screenState) {
3
NfcDiscoveryParameters.Builder paramsBuilder = NfcDiscoveryParameters.newBuilder();
4
//当屏幕状态>= NFC_POLLING_MODE,而如下:
5
//static final int NFC_POLLING_MODE = ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED;
6
//其实就是在亮屏并且处于解锁状态的时候,或mIsTaskBoot为true,mIsTaskBoot这个变量只有在处于初始化
7
//阶段,NfcService从构造的结尾处进行Nfc的启动.
8
// Polling;mIsInterruptedByCamera :是否被camera打断.
9
if (((screenState >= NFC_POLLING_MODE)||mIsTaskBoot) && !mIsInterruptedByCamera) {
10
//mReaderModeParams是在setReaderMode()这个接口中被设置的,应该是第三方app,在它们
11
//的应用界面想要把手机作为reader的时候会打印。
12
//当前NFC读模式开启后,按照协议,看看当前的Tag属于那种类型的Tag,然后设置techMask.
13
if (mReaderModeParams != null) {
14
int techMask = 0;
15
if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_A) != 0)
16
techMask |= NFC_POLL_A;
17
if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_B) != 0)
18
techMask |= NFC_POLL_B;
19
if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_F) != 0)
20
techMask |= NFC_POLL_F;
21
if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_V) != 0)
22
techMask |= NFC_POLL_ISO15693;
23
if ((mReaderModeParams.flags & NfcAdapter.FLAG_READER_NFC_BARCODE) != 0)
24
techMask |= NFC_POLL_KOVIO;
25
paramsBuilder.setTechMask(techMask);
26
paramsBuilder.setEnableReaderMode(true);
27
} else {
28
//系统内部的会设置为NFC_POLL_DEFAULT这个参数 对应:
29
//static final int NFC_POLL_DEFAULT = -1; 但是感觉传入到native层的时候,可能根据这个
30
//有个默认的设置.
31
paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
32
paramsBuilder.setEnableP2p(true);
33
}
34
//锁屏并且在ProvisionMode
35
} else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED && mInProvisionMode) {
36
paramsBuilder.setTechMask(NfcDiscoveryParameters.NFC_POLL_DEFAULT);
37
paramsBuilder.setEnableP2p(true);
38
//当有人调用addNfcUnlockHandler的时候,isLockscreenPollingEnabled才可能被设置为true,
39
//发现在sony的设计中LockScreenHeadsetHandover的构造处有添加.
40
//注意此时的屏幕状态是SCREEN_STATE_ON_LOCKED.就是亮屏,但是锁着那!
41
} else if (screenState == ScreenStateHelper.SCREEN_STATE_ON_LOCKED &&
42
mNfcUnlockManager.isLockscreenPollingEnabled()) {
43
// For lock-screen tags, no low-power polling
44
paramsBuilder.setTechMask(mNfcUnlockManager.getLockscreenPollMask());
45
paramsBuilder.setEnableLowPowerDiscovery(false);
46
paramsBuilder.setEnableP2p(false);
47
}
48
//mIsHceCapable代表是否具有卡模拟的功能。不插卡的时候也是true,可能是针对HCE的?
49
if (mIsHceCapable && mScreenState >= ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
50
// Host routing is always enabled at lock screen or later
51
paramsBuilder.setEnableHostRouting(true);
52
}
53
//只要commit过routingtable,或者设置过屏幕状态,或者换过卡,等等mIsRoutingTableDirty会为true.
54
if(mIsRoutingTableDirty) {
55
mIsRoutingTableDirty = false;
56
int protoRoute = mNxpPrefs.getInt("PREF_MIFARE_DESFIRE_PROTO_ROUTE_ID",
57
GetDefaultMifareDesfireRouteEntry());
58
int defaultRoute=mNxpPrefs.getInt("PREF_SET_DEFAULT_ROUTE_ID",
59
GetDefaultRouteEntry());
60
int techRoute=mNxpPrefs.getInt("PREF_MIFARE_CLT_ROUTE_ID",
61
GetDefaultMifateCLTRouteEntry());
62
defaultRoute = NfcCertDebugModeUtil.calculateDefaultRoute(defaultRoute,
63
mDeviceHost.getDefaultAidPowerState(), ROUTE_LOC_MASK);
64
if (DBG) Log.d(TAG, "Set default Route Entry");
65
setDefaultRoute(defaultRoute, protoRoute, techRoute);
66
}
67
...
68
return paramsBuilder.build(); //返回对应字符串,代表相关的参数
69
}
以上是关于NFC工作的RF状态的描述分析,下面开始分析,当NFC检测到remote tag的时候的回调。
最终native层通过NativeNfcManager.cpp中的
1
gCachedNfcManagerNotifyNdefMessageListeners = e->GetMethodID(cls.get(),
2
"notifyNdefMessageListeners", "(Lcom/android/nfc/dhimpl/NativeNfcTag;)V");
回调于NfcTag.cpp中的createNativeNfcTag(..)方法,然后通过JNI调用到NativeNfcManager.java中的
1
private void notifyNdefMessageListeners(NativeNfcTag tag) {
2
mListener.onRemoteEndpointDiscovered(tag);
3
}
mListener的实现就是NfcService,又重新回到Nfcservice中
1
@Override
2
public void onRemoteEndpointDiscovered(TagEndpoint tag) {
3
sendMessage(NfcService.MSG_NDEF_TAG, tag);
4
}
5
void sendMessage(int what, Object obj) {
6
Message msg = mHandler.obtainMessage();
7
msg.what = what;
8
msg.obj = obj;
9
mHandler.sendMessage(msg);
10
}
到此为止,native层对发现的tag进行了一系列的初始化和封装操作,就是按照ndef协议把Tag的消息封
装到TagEndpoint当中,TagEndpoint就是代表了一个远端的Nfc tag.
然后执行到mHandler中的MSG_NDEF_TAG
1
case MSG_NDEF_TAG:
2
if (DBG) Log.d(TAG, "Tag detected, notifying applications");
3
......
4
//当有别人调用setReaderMode()接口去设置mReaderModeParams的时候.
5
//如第三方app模拟reader.(一般都是在第三方app的reader/write界面,由它们调用)
6
synchronized (NfcService.this) {
7
readerParams = mReaderModeParams;
8
}
9
if (readerParams != null) {
10
presenceCheckDelay = readerParams.presenceCheckDelay;
11
//如果FLAG_READER_SKIP_NDEF_CHECK标记位不为0,那么直接开始调用dispatchTagEndpoint分发
12
if ((readerParams.flags & NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK) != 0) {
13
if (DBG) Log.d(TAG, "Skipping NDEF detection in reader mode");
14
tag.startPresenceChecking(presenceCheckDelay, callback);
15
dispatchTagEndpoint(tag, readerParams);
16
break;
17
}
18
}
19
//当是NFC Barcode的时候也是直接分发,看其实意思是解析NFC条形码的时候
20
if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
21
......
22
if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
23
tag.startPresenceChecking(presenceCheckDelay, callback);
24
dispatchTagEndpoint(tag, readerParams);
25
break;
26
}
27
//去调用NativeNfcTag的findAndReadNdef,进行相关初始化后把native层的数据按照NDEF
28
//协议封装成java中的类NdefMessage.(此时就是读取NDEF格式的信息了)
29
NdefMessage ndefMsg = tag.findAndReadNdef();
30
//解析的消息无法被实例化成NDEF的时候。
31
if (ndefMsg == null) {
32
// First try to see if this was a bad tag read
33
if (!tag.reconnect()) {
34
tag.disconnect();
35
//当是亮屏的时候弹出提示信息.
36
if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED) {
37
//"Read error. Try again"
38
String toastString = mContext.getString(
39
R.string.nfc_strings_toast_prompt_touch_again_txt);
40
if (!ToastMaster.isSameToastShown(toastString)) {
41
ToastMaster.showToast(mContext, toastString);
42
}
43
}
44
break;
45
}
46
}
47
//这个如名字是抖动的tag,就是由于距离没控制好,一直检测到同一个tag的时候。
48
//应该就是这个Tag检测完,没有离开范围,就不会再次检测
49
if (debounceTagUid != null) {
50
// If we're debouncing and the UID or the NDEF message of the tag match,
51
// don't dispatch but drop it.
52
......
53
}
54
mLastReadNdefMessage = ndefMsg;
55
tag.startPresenceChecking(presenceCheckDelay, callback);
56
//解析出问题的ndef消息也要分发出去.
57
dispatchTagEndpoint(tag, readerParams);
58
break;
59
//case MSG_NDEF_TAG over.
至此开始准备进行读取Tag。
findAndReadNdef的解析,位于NativeNfcTag.这个方法中的注释为我们的分析带来很多遍历,此处需要
特别注意:NativeNfcTag是Nfc Tag在java层的一个代表,它在native层由NfcTag对象来表示,在NfcTag.cpp
中有如下方法用于创建NativeNfcTag对象,并且是实例化相应的参数,注释写的很详细,源码如下:
1
/*******************************************************************************
2
**
3
** Function: createNativeNfcTag
4
**
5
** Description: Create a brand new Java NativeNfcTag object;
6
** fill the objects's member variables with data;
7
** notify NFC service;
8
** activationData: data from activation.
9
**
10
** Returns: None
11
**
12
*******************************************************************************/
13
void NfcTag::createNativeNfcTag (tNFA_ACTIVATED& activationData)
14
{
15
static const char fn [] = "NfcTag::createNativeNfcTag";
16
ALOGV("%s: enter", fn);
17
18
JNIEnv* e = NULL;
19
ScopedAttach attach(mNativeData->vm, &e);
20
if (e == NULL)
21
{
22
ALOGE("%s: jni env is null", fn);
23
return;
24
}
25
26
ScopedLocalRef<jclass> tag_cls(e, e->GetObjectClass(mNativeData->cached_NfcTag));
27
if (e->ExceptionCheck())
28
{
29
e->ExceptionClear();
30
ALOGE("%s: failed to get class", fn);
31
return;
32
}
33
34
//create a new Java NativeNfcTag object
35
jmethodID ctor = e->GetMethodID(tag_cls.get(), "<init>", "()V");
36
ScopedLocalRef<jobject> tag(e, e->NewObject(tag_cls.get(), ctor));
37
38
//fill NativeNfcTag's mProtocols, mTechList, mTechHandles, mTechLibNfcTypes
39
fillNativeNfcTagMembers1(e, tag_cls.get(), tag.get());
40
41
//fill NativeNfcTag's members: mHandle, mConnectedTechnology
42
fillNativeNfcTagMembers2(e, tag_cls.get(), tag.get(), activationData);
43
44
//fill NativeNfcTag's members: mTechPollBytes
45
fillNativeNfcTagMembers3(e, tag_cls.get(), tag.get(), activationData);
46
47
//fill NativeNfcTag's members: mTechActBytes
48
fillNativeNfcTagMembers4(e, tag_cls.get(), tag.get(), activationData);
49
50
//fill NativeNfcTag's members: mUid
51
fillNativeNfcTagMembers5(e, tag_cls.get(), tag.get(), activationData);
52
53
if (mNativeData->tag != NULL)
54
{
55
e->DeleteGlobalRef(mNativeData->tag);
56
}
57
mNativeData->tag = e->NewGlobalRef(tag.get());
58
59
ALOGV("%s; mNumDiscNtf=%x", fn,mNumDiscNtf);
60
if(!mNumDiscNtf || NfcTag::getInstance().checkNextValidProtocol() == -1)
61
{
62
//notify NFC service about this new tag
63
mNumDiscNtf = 0;
64
ALOGV("%s: try notify nfc service", fn);
65
storeActivationParams();
66
e->CallVoidMethod(mNativeData->manager,
67
android::gCachedNfcManagerNotifyNdefMessageListeners, tag.get());
68
if (e->ExceptionCheck())
69
{
70
e->ExceptionClear();
71
ALOGE("%s: fail notify nfc service", fn);
72
}
73
deleteglobaldata(e);
74
}
75
else
76
{
77
ALOGV("%s: Selecting next tag", fn);
78
}
79
80
ALOGV("%s: exit", fn);
81
}
如上需要注意,每次检测到一个Tag都会调用createNativeNfcTag,去实例化一个native对应的对象(刷一
次卡创建一个),然后实例化各个变量。也因此如下变量:
1
// mConnectedHandle stores the *real* libnfc handle
2
// that we're connected to.
3
private int mConnectedHandle;
每次都是0,因为是默认值嘛!而且在native层也没有对它进行初始化。至于NativeNfcTag这个类的销
毁,好像出了这个方法就销毁了(native层)?Java层在相应的方法中使用完毕以后也就释放了
下面以findAndReadNdef为切入点,结合注释看一下connect和read Tag的流程.
1
@Override
2
public NdefMessage findAndReadNdef(){
3
//去获取当前Tag支持的所有的tech
4
//如下technologies、handles都是在native层就实例化好的.
5
//TagTechnology有很多种, NFC_A、NFC_B、ISO_DEP、NFC_F、NFC_V.
6
//关于technologies和handles也需要多说一下,暂时对这块认知不高,通过Log观察到如下:
7
//使用了四张平常的卡进行测试抓取, 每次technologies和数量和handles的数量都是一致的,
8
//technologies是卡片支持的协议,对应于TagTechnology.java中的成员变量.
9
//handles 在这次试验的手机上值都是1,无论size是对少,每个位置都是1,而handles的添加在java层
10
//都是对应这个变量 private int mConnectedHandle;前面有注释是说代表了libnfc的handle,那么
11
//感觉一般的平台肯定是用的一个libnfc库呀,难道有些会用两个libnfc?然后去进行选择?
12
int[] technologies = getTechList();
13
int[] handles = mTechHandles;
14
NdefMessage ndefMsg = null;
15
boolean foundFormattable = false;
16
int formattableHandle = 0;
17
int formattableLibNfcType = 0;
18
int status;
19
for (int techIndex = 0; techIndex < technologies.length; techIndex++) {
20
for (int i = 0; i < techIndex; i++) {
21
//高效处理,我们目前handle都是一样的情况
22
if (handles[i] == handles[techIndex]) {
23
continue; // don't check duplicate handles
24
}
25
}
26
//网上说明:判断connectedHandle与当前Index对应的handle的关系,并更新状态,。
27
//自己理解不深,源码见后面.
28
status = connectWithStatus(technologies[techIndex]);
29
//连接失败直接跳过本次循环,连接下一个Tech!!
30
if (status != 0) {
31
Log.d(TAG, "Connect Failed - status = "+ status);
32
if (status == STATUS_CODE_TARGET_LOST) {
33
break;
34
}
35
continue; // try next handle
36
}
37
if (!foundFormattable) {
38
//如果是标准的Ndef格式,进行如下操作,自己测试的四个卡都是.
39
if (isNdefFormatable()) {
40
foundFormattable = true;
41
formattableHandle = getConnectedHandle();
42
formattableLibNfcType = getConnectedLibNfcType();
43
}
44
//再次connect
45
reconnect();
46
}
47
48
int[] ndefinfo = new int[2];
49
//检查当前tag中ndef数据的合法性,传入ndefinfo会走到native层,进行数据的赋值.
50
status = checkNdefWithStatus(ndefinfo);
51
if (status != 0) {
52
Log.d(TAG, "Check NDEF Failed - status = " + status);
53
if (status == STATUS_CODE_TARGET_LOST) {
54
break;
55
}
56
continue; // try next handle
57
}
58
// found our NDEF handle
59
boolean generateEmptyNdef = false;
60
//check完以后ndefinfo这个里面的数据,正常情况下就是完整的了。
61
int supportedNdefLength = ndefinfo[0];
62
int cardState = ndefinfo[1];
63
//此处才是真正的读取,读取tag中的数据,读出来的是字节数组。
64
//注意此处经常丢失Log
65
byte[] buff = readNdef();
66
if (buff != null && buff.length > 0) {
67
try {
68
//正常的应该走到这里,通过获取的数据实例化NdefMessage.
69
//在NdefMessage实例化的时候就按照NDEF的协议去解析这个byte数组
70
//中的数据,然后封装成各个类和相应的字段供我们到时候直接调用
71
ndefMsg = new NdefMessage(buff);
72
//把检测到的数据都保存起来.
73
addNdefTechnology(ndefMsg,
74
getConnectedHandle(),
75
getConnectedLibNfcType(),
76
getConnectedTechnology(),
77
supportedNdefLength, cardState);
78
foundFormattable = false;
79
//最后又进行了一次连接,不知道有何作用
80
reconnect();
81
} catch (FormatException e) {
82
// Create an intent anyway, without NDEF messages
83
generateEmptyNdef = true;
84
}
85
} else if(buff != null){
86
// Empty buffer, unformatted tags fall into this case
87
generateEmptyNdef = true;
88
}
89
//当产生异常的时候generateEmptyNdef为true的一些处理
90
if (generateEmptyNdef) {
91
ndefMsg = null;
92
//存一个空NdefMessage
93
addNdefTechnology(null,
94
getConnectedHandle(),
95
getConnectedLibNfcType(),
96
getConnectedTechnology(),
97
supportedNdefLength, cardState);
98
foundFormattable = false;
99
reconnect();
100
}
101
break;
102
}
103
......
104
return ndefMsg;
105
}
connectWithStatus源码:(注释挺多的,容易看懂但不容易理解)
1
private native int doConnect(int handle);
2
public synchronized int connectWithStatus(int technology) {
3
......
4
int status = -1;
5
for (int i = 0; i < mTechList.length; i++) {
6
//循环遍历所有的tech,找到需要connect的tech
7
if (mTechList[i] == technology) {
8
//当前的tag被检测到,第一次走到这里的时候mConnectedHandle是默认值,
9
//因为没有在native层进行实例化,所以是mConnectedHandle = 0;
10
// Get the handle and connect, if not already connected
11
if (mConnectedHandle != mTechHandles[i]) {
12
// We're not yet connected to this handle, there are
13
// a few scenario's here:
14
// 1) We are not connected to anything yet - allow
15
// 2) We are connected to a technology which has
16
// a different handle (multi-protocol tag); we support
17
// switching to that.
18
if (mConnectedHandle == -1) {
19
//这个情况,Log一直观察不到,无论是重启/刷机的第一次,还是平常都不行
20
//感觉也正常,因为可能是libnfc只要连接上,就不会初始化成-1.
21
// Not connected yet
22
//status = doConnect(mTechHandles[i]);
23
Log.d(TAG," readerParams doConnect");
24
status = doConnect(i);
25
} else {
26
//调用reconnectWithStatus传入handle.(暂时发现每个tag的handle都是一样的)
27
// Connect to a tech with a different handle
28
Log.d(TAG," readerParams Connect to a tech with a different handle");
29
status = reconnectWithStatus(i);
30
}
31
//如果成功链接,mConnectedHandle都是1(在我这个测试手机上),按照前面的变量分析的话,
32
//也可以理解
33
if (status == 0) {
34
mConnectedHandle = mTechHandles[i];
35
mConnectedTechIndex = i;(把tech所在的正确的index传入)
36
}
37
} else {
38
//按照目前的手机和Log和Tag的分析都没有走到这里,暂时不太理解
39
// 1) We are connected to a technology which has the same
40
// handle; we do not support connecting at a different
41
// level (libnfc auto-activates to the max level on
42
// any handle).
43
// 2) We are connecting to the ndef technology - always
44
// allowed.
45
if ((technology == TagTechnology.NDEF) ||
46
(technology == TagTechnology.NDEF_FORMATABLE)) {
47
// special case for NDEF, this will cause switch to ISO_DEP frame intf
48
i = 0;
49
// status = 0;
50
}
51
status = reconnectWithStatus(i);
52
......
53
54
if (status == 0) {
55
mConnectedTechIndex = i;
56
// Handle was already identical
57
}
58
}
59
break;
60
}
61
}
62
......
63
return status;
64
}
reconnectWithStatus()的相关源码流程:
1
native int doHandleReconnect(int handle);
2
public synchronized int reconnectWithStatus(int handle) {
3
......
4
//最后就是调用到native的方法去做进一步的连接操作.
5
int status = doHandleReconnect(handle);
6
......
7
return status;
8
}
reconnect相关源码分析.
1
@Override
2
public synchronized boolean reconnect() {
3
return reconnectWithStatus() == 0;
4
}
5
native int doReconnect();
6
public synchronized int reconnectWithStatus() {
7
......
8
int status = doReconnect();
9
......
10
return status;
11
}
checkNdefWithStatus相关源码分析
1
private native int doCheckNdef(int[] ndefinfo);
2
private synchronized int checkNdefWithStatus(int[] ndefinfo) {
3
......
4
int status = doCheckNdef(ndefinfo);
5
......
6
return status;
7
}
addNdefTechnology相关源码
1
public void addNdefTechnology(NdefMessage msg, int handle, int libnfcType,
2
int javaType, int maxLength, int cardState) {
3
synchronized (this) {
4
addTechnology(TagTechnology.NDEF, handle, libnfcType);
5
6
Bundle extras = new Bundle();
7
extras.putParcelable(Ndef.EXTRA_NDEF_MSG, msg);
8
extras.putInt(Ndef.EXTRA_NDEF_MAXLENGTH, maxLength);
9
extras.putInt(Ndef.EXTRA_NDEF_CARDSTATE, cardState);
10
extras.putInt(Ndef.EXTRA_NDEF_TYPE, getNdefType(libnfcType, javaType));
11
Log.d(TAG,"addNdefTechnology readerParams mTechExtras = "+mTechExtras);
12
//getTechExtras内部会更具Tech,创建出一个Bundle,最终NfcService可以获取这个然后取出
13
//来其中的数据,以及重要的NdefMessage.
14
if (mTechExtras == null) {
15
// This will build the tech extra's for the first time,
16
// including a NULL ref for the NDEF tech we generated above.
17
Bundle[] builtTechExtras = getTechExtras();
18
builtTechExtras[builtTechExtras.length - 1] = extras;
19
}
20
else {
21
// Tech extras were built before, patch the NDEF one in
22
Bundle[] oldTechExtras = getTechExtras();
23
Bundle[] newTechExtras = new Bundle[oldTechExtras.length + 1];
24
System.arraycopy(oldTechExtras, 0, newTechExtras, 0, oldTechExtras.length);
25
newTechExtras[oldTechExtras.length] = extras;
26
mTechExtras = newTechExtras;
27
}
28
}
29
}
doRead()相关源码分析.
1
private native byte[] doRead();
2
@Override
3
public synchronized byte[] readNdef() {
4
......
5
byte[] result = doRead();
6
......
7
return result;
8
}
至此和findAndReadNdef()相关的都源码进行了简单的跟踪处理。再回到前面的NfcService中的
case MSG_NDEF_TAG: 再往下就是真正分发的地方dispatchTagEndpoint了。
1
private void dispatchTagEndpoint(TagEndpoint tagEndpoint, ReaderModeParams readerParams){
2
//Tag用来封装一个已经被发现的Tag.Tag类是framework提供的api
3
//tagEndpoint.getTechExtras():就包含我们最后addNdefTechnology的时候存入的NdefMessage.
4
Tag tag = new Tag(tagEndpoint.getUid(), tagEndpoint.getTechList(),
5
tagEndpoint.getTechExtras(), tagEndpoint.getHandle(), mNfcTagService);
6
//把tagEndpoint以 key = tagEndpoint.gethandle;value = tagEndpoint放入到集合中
7
//final HashMap<Integer, Object> mObjectMap = new HashMap<Integer, Object>();
8
//由此手机看来,handle一样,那么一次检测基本就存一个,第一个连接成功Tech.
9
registerTagObject(tagEndpoint);
10
//当有第三方app
11
if (readerParams != null) {
12
try {
13
if ((readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0) {
14
playSound(SOUND_END);
15
}
16
if (readerParams.callback != null) {
17
//调用回调onTagDiscovered.
18
readerParams.callback.onTagDiscovered(tag);
19
return;
20
} else {
21
// Follow normal dispatch below
22
}
23
} ...
24
}
25
//正真开始分发的地方.
26
//mNfcDispatcher是NfcDispatcher实例,初始化也是在NfcService启动的时候在构造当中
27
//mNfcDispatcher = new NfcDispatcher(mContext, mHandoverDataParser, mInProvisionMode);
28
//传入的mHandoverDataParser = new HandoverDataParser();同样是在构造当中
29
int dispatchResult = mNfcDispatcher.dispatchTag(tag);
30
//分发完毕后的处理:
31
//当失败的时候
32
if (dispatchResult == NfcDispatcher.DISPATCH_FAIL) {
33
unregisterObject(tagEndpoint.getHandle());
34
//屏幕处于亮屏且解锁状态的时候:
35
//弹出:No supported apps for this tag installed on this device
36
//表示没有任何的activity处理当前的分发!
37
if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED) {
38
String toastString = mContext.getString(
39
R.string.nfc_strings_toast_prompt_read_error_txt);
40
//弹出Toast进行提示.
41
if (!ToastMaster.isSameToastShown(toastString)) {
42
ToastMaster.showToast(mContext, toastString);
43
playSound(SOUND_ERROR);
44
}
45
}
46
} else if (dispatchResult == NfcDispatcher.DISPATCH_SUCCESS) {
47
//成功的时候,播放震动和声音.
48
if (mAudioManager.getRingerMode() != mAudioManager.RINGER_MODE_SILENT) {
49
mVibrator.vibrate(200);
50
}
51
playSound(SOUND_END);
52
}
53
}
可以看到最最重要的就是NfcDispatcher中的dispatchTag(Tag)了,进入到NfcDispatcher类,
此类从名字也能看出主要功能,它就是分发NFC的actions然后去开启指定的activity。
阅读下面的流程代码之前,最好对Android NFC的TAG的分发机制有个整体了解,这样和代码对应上就更为轻松了。
整体的代码是按照Android Tag的分发优先级来决定的.
1
public int dispatchTag(Tag tag) {
2
PendingIntent overrideIntent;
3
IntentFilter[] overrideFilters;
4
String[][] overrideTechLists;
5
String[] provisioningMimes;
6
boolean provisioningOnly;
7
synchronized (this) {
8
//overrideFilters的赋值是外部的app,运行在前台,想要处理Nfc的Tag使用的
9
//外部通过调用NfcService的setForegroundDispatch来实现。
10
overrideFilters = mOverrideFilters;
11
overrideIntent = mOverrideIntent;
12
overrideTechLists = mOverrideTechLists;
13
provisioningOnly = mProvisioningOnly;
14
provisioningMimes = mProvisioningMimes;
15
}
16
//在屏幕是SCREEN_STATE_ON_LOCKED的状态下尝试调用handleNfcUnlock去解锁屏幕。
17
boolean screenUnlocked = false;
18
if (!provisioningOnly &&
19
mScreenStateHelper.checkScreenState() ==
20
ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
21
screenUnlocked = handleNfcUnlock(tag);
22
if (!screenUnlocked) {
23
return DISPATCH_FAIL;
24
}
25
}
26
NdefMessage message = null;
27
//将Tag解析成Ndef的格式.此处是所读取的卡片的所有Tech中只要有Ndef的Tech即可.
28
//返回null的时候证明这个Tag不是NDEF formatted的,或者说这个Tag虽然是NDEF formatted的
29
//但是不是Android所支持的.
30
Ndef ndef = Ndef.get(tag);
31
if (ndef != null) {
32
//再通过这样获取到NdefMessage,此处的疑问,前面不是已经获取到NdefMessage
33
//为什么还要再用NdefMessage生成个Tag,然后在通过Tag获取,看起来好像是为了方便framewok
34
//统一接口,供外部调用.
35
message = ndef.getCachedNdefMessage();
36
} else {
37
//当是null的时候,先看看是不是NfcBarcode Tech
38
NfcBarcode nfcBarcode = NfcBarcode.get(tag);
39
if (nfcBarcode != null && nfcBarcode.getType() == NfcBarcode.TYPE_KOVIO) {
40
message = decodeNfcBarcodeUri(nfcBarcode);
41
}
42
}
43
if (DBG) Log.d(TAG, "dispatch tag: " + tag.toString() + " message: " + message);
44
//DispatchInfo是在Tag分发的过程中的帮助类,源码分析见后面
45
DispatchInfo dispatch = new DispatchInfo(mContext, tag, message);
46
//Tells the ActivityManager to resume allowing app switches.
47
resumeAppSwitches();
48
49
//如果正在运行的APP有定义了前台分发机制,则会走到这里,就是某个app注册了一些接口
50
//并且运行在前台,它想去读取这些信息
51
if (tryOverrides(dispatch, tag, message, overrideIntent, overrideFilters,
52
overrideTechLists)) {
53
return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
54
}
55
//尝试使用Handover来分发消息.就是带Nfc的蓝牙鼠标、键盘等.可以看到在普通的系统分发之前.
56
//通过BT传输图片不属于这个,那个是P2P的流程中的.忽然想起来这应该就是所谓的Hadover和Beam区分吧.
57
if (tryPeripheralHandover(message)) {
58
if (DBG) Log.i(TAG, "matched BT HANDOVER");
59
return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
60
}
61
//WIFI相关的暂无了解
62
if (NfcWifiProtectedSetup.tryNfcWifiSetup(ndef, mContext)) {
63
if (DBG) Log.i(TAG, "matched NFC WPS TOKEN");
64
return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
65
}
66
......
67
//下面开始根据优先级先将Tag消息发送给对action为ACTION_NDEF_DISCOVERED感兴趣的APP处理 .
68
if (tryNdef(dispatch, message)) {
69
return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
70
}
71
//将Tag消息发送给对ACTION_TECH_DISCOVERED感兴趣的APP处理
72
if (tryTech(dispatch, tag)) {
73
return DISPATCH_SUCCESS;
74
}
75
//如上两个action相关的activity都未处理的时候
76
//将intent的action设置为ACTION_TAG_DISCOVERED
77
dispatch.setTagIntent();
78
if (dispatch.tryStartActivity()) {
79
if (DBG) Log.i(TAG, "matched TAG");
80
return DISPATCH_SUCCESS;
81
}
82
//都无法处理就返回false.
83
if (DBG) Log.i(TAG, "no match");
84
return DISPATCH_FAIL;
85
}
DispatchInfo类的源码分析:
1
/**
2
* Helper for re-used objects and methods during a single tag dispatch.
3
*/
4
static class DispatchInfo {
5
public final Intent intent;
6
7
final Intent rootIntent;
8
final Uri ndefUri;
9
final String ndefMimeType;
10
final PackageManager packageManager;
11
final Context context;
12
final Tag tag;
13
14
public DispatchInfo(Context context, Tag tag, NdefMessage message) {
15
//构造会直接实例化一个intent,然后把tag先放入.
16
intent = new Intent();
17
intent.putExtra(NfcAdapter.EXTRA_TAG, tag);
18
intent.putExtra(NfcAdapter.EXTRA_ID, tag.getId());
19
if (message != null) {
20
intent.putExtra(NfcAdapter.EXTRA_NDEF_MESSAGES, new NdefMessage[] {message});
21
ndefUri = message.getRecords()[0].toUri();
22
ndefMimeType = message.getRecords()[0].toMimeType();
23
} else {
24
//当传入的是null的时候,就是Ndef.get(tag)不能获取正确的值.
25
ndefUri = null;
26
ndefMimeType = null;
27
}
28
//这个NfcRootActivity会直接去启动,Intent携带的EXTRA_LAUNCH_INTENT对应的activity
29
//对应到下面也就是启动,最一开始的intent = new Intent();
30
//此时把你要启动的activity对应的intent添加到成员变量intent中即可.
31
//这样好像是为了提供NFC root task.
32
rootIntent = new Intent(context, NfcRootActivity.class);
33
rootIntent.putExtra(NfcRootActivity.EXTRA_LAUNCH_INTENT, intent);
34
rootIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
35
36
this.tag = tag;
37
this.context = context;
38
packageManager = context.getPackageManager();
39
}
40
//设置注册action:ACTION_NDEF_DISCOVERED的intent.
41
public Intent setNdefIntent() {
42
intent.setAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
43
if (ndefUri != null) {
44
intent.setData(ndefUri);
45
return intent;
46
} else if (ndefMimeType != null) {
47
intent.setType(ndefMimeType);
48
return intent;
49
}
50
return null;
51
}
52
//设置注册action:ACTION_TECH_DISCOVERED的intent.
53
public Intent setTechIntent() {
54
intent.setData(null);
55
intent.setType(null);
56
intent.setAction(NfcAdapter.ACTION_TECH_DISCOVERED);
57
return intent;
58
}
59
//设置注册action:ACTION_TAG_DISCOVERED的intent.
60
public Intent setTagIntent() {
61
intent.setData(null);
62
intent.setType(null);
63
intent.setAction(NfcAdapter.ACTION_TAG_DISCOVERED);
64
return intent;
65
}
66
67
//以成员变量intent,启动所有的注册的activity
68
boolean tryStartActivity() {
69
//遍历所有符合成员变量intent要求的acitivity
70
List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(intent, 0,
71
ActivityManager.getCurrentUser());
72
if (activities.size() > 0) {
73
//直接启动
74
context.startActivityAsUser(rootIntent, UserHandle.CURRENT);
75
return true;
76
}
77
return false;
78
}
79
//以特定的intentToStart,启动所有注册的activity
80
boolean tryStartActivity(Intent intentToStart) {
81
List<ResolveInfo> activities = packageManager.queryIntentActivitiesAsUser(
82
intentToStart, 0, ActivityManager.getCurrentUser());
83
if (activities.size() > 0) {
84
rootIntent.putExtra(NfcRootActivity.EXTRA_LAUNCH_INTENT, intentToStart);
85
context.startActivityAsUser(rootIntent, UserHandle.CURRENT);
86
NfcIddEvent.NfcTag.dispatchedToApp(tag, activities);
87
return true;
88
}
89
return false;
90
}
91
}
下面先介绍一个接口,用于运行在前台的app注册,拦截分发时间NfcService的setForegroundDispatch最
终会调用到NfcDispatcher中的.
1
public synchronized void setForegroundDispatch(PendingIntent intent,
2
IntentFilter[] filters, String[][] techLists) {
3
if (DBG) Log.d(TAG, "Set Foreground Dispatch");
4
mOverrideIntent = intent;
5
mOverrideFilters = filters;
6
mOverrideTechLists = techLists;
7
}
第三方app使用前台分发系统时的调用
1
boolean tryOverrides(DispatchInfo dispatch, Tag tag, NdefMessage message, PendingIntent overrideIntent,
2
IntentFilter[] overrideFilters, String[][] overrideTechLists) {
3
......
4
// 首先是当NdefMessage存在的时候,先去判断NDEF格式的消息
5
if (message != null) {
6
intent = dispatch.setNdefIntent();
7
//当当前的NdefMessage中是对应的NDEF消息时,使用传入的PendingIntent去启动对应的activity
8
if (intent != null &&
9
isFilterMatch(intent, overrideFilters, overrideTechLists != null)) {
10
try {
11
//直接启动
12
overrideIntent.send(mContext, Activity.RESULT_OK, intent);
13
if (DBG) Log.i(TAG, "matched NDEF override");
14
return true;
15
} catch (CanceledException e) {
16
return false;
17
}
18
}
19
}
20
// TECH
21
intent = dispatch.setTechIntent();
22
//当传入的Tag的Technolg也是支持的时候,把action设置成ACTION_NDEF_DISCOVERED去启动
23
if (isTechMatch(tag, overrideTechLists)) {
24
try {
25
overrideIntent.send(mContext, Activity.RESULT_OK, intent);
26
if (DBG) Log.i(TAG, "matched TECH override");
27
return true;
28
} catch (CanceledException e) {
29
return false;
30
}
31
}
32
// TAG 和上面同理。
33
intent = dispatch.setTagIntent();
34
if (isFilterMatch(intent, overrideFilters, overrideTechLists != null)) {
35
try {
36
overrideIntent.send(mContext, Activity.RESULT_OK, intent);
37
if (DBG) Log.i(TAG, "matched TAG override");
38
return true;
39
} catch (CanceledException e) {
40
return false;
41
}
42
}
43
return false;
44
}
接下来是通过tryPeripheralHandover的,就是交由Bt进行发送的数据的处理
1
public boolean tryPeripheralHandover(NdefMessage m) {
2
//消息为空,或者说设备不支持蓝牙,那么就直接返回
3
if (m == null || !mDeviceSupportsBluetooth) return false;
4
if (DBG) Log.d(TAG, "tryHandover(): " + m.toString());
5
//假如是进行Handover的时候,会按照Nfc Form中的Handover相关的协议从NdefMessage中解析出正确的数据
6
HandoverDataParser.BluetoothHandoverData handover =
7
mHandoverDataParser.parseBluetooth(m);
8
......
9
//得到handover的各个参数以后,设置到intent内,并启动PeripheralHandoverService这个service.
10
//通过下面可以看到,主要有BT的 device、name、uuid、等
11
Intent intent = new Intent(mContext, PeripheralHandoverService.class);
12
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_DEVICE, handover.device);
13
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_NAME, handover.name);
14
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_TRANSPORT,
15
handover.transport);
16
if (handover.oobData != null) {
17
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_OOB_DATA,
18
handover.oobData);
19
}
20
if (handover.uuids != null) {
21
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_UUIDS, handover.uuids);
22
}
23
if (handover.bluetoothClass != null) {
24
intent.putExtra(PeripheralHandoverService.EXTRA_PERIPHERAL_CLASS,
25
handover.bluetoothClass);
26
}
27
intent.putExtra(PeripheralHandoverService.EXTRA_CLIENT, mMessenger);
28
intent.putExtra(PeripheralHandoverService.EXTRA_BT_ENABLED,
29
mBluetoothEnabledByNfc.get());
30
//国内过CTA检测的时候的弹框
31
if (CtaUtils.showCtaBtDialogIfNeeded(mContext, null, intent, null)) {
32
return true;
33
}
34
//最后启动PeripheralHandoverService.
35
mContext.startServiceAsUser(intent, UserHandle.CURRENT);
36
return true;
37
}
关于PeripheralHandoverService的介绍
这个service主要是用于负责Handover,也就是链接蓝牙键盘、Speaker等.
1
public class PeripheralHandoverService extends Service
2
implements BluetoothPeripheralHandover.Callback {
3
......
4
public PeripheralHandoverService() {
5
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
6
mHandler = new MessageHandler();
7
mMessenger = new Messenger(mHandler);
8
mBluetoothHeadsetConnected = false;
9
mBluetoothEnabledByNfc = false;
10
mStartId = 0;
11
}
12
@Override
13
public void onCreate() {
14
super.onCreate();
15
mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
16
//注册一个广播监听蓝牙状态,是否打开等.
17
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
18
registerReceiver(mBluetoothStatusReceiver, filter);
19
}
20
21
@Override
22
public int onStartCommand(Intent intent, int flags, int startId) {
23
......
24
//进一步的回去打开BT,前面也注册了广播,在收到蓝牙开启广播以后开始做真正的Handover
25
//去连接键盘了,等等.
26
if (doPeripheralHandover(intent.getExtras())) {
27
return START_STICKY;
28
}
29
......
30
}
31
}
Handover到时候专门在分析源码相关的源码,此处我们回到前面的dispatchTag()方法中,然后就是
按照Android的分发系统,优先处理注册了action为NfcAdapter.ACTION_NDEF_DISCOVERED的
1
boolean tryNdef(DispatchInfo dispatch, NdefMessage message) {
2
......
3
//为dispatch设置ACTION_NDEF_DISCOVERED相关的intent.
4
Intent intent = dispatch.setNdefIntent();
5
if (intent == null) return false;
6
//如果发送的NdefMessage包含打开这个消息的包的信息(AAR)
7
//那么就用指定的包处理这个Tag消息
8
List<String> aarPackages = extractAarPackages(message);
9
for (String pkg : aarPackages) {
10
dispatch.intent.setPackage(pkg);
11
//直接使用指定的apk去打开
12
if (dispatch.tryStartActivity()) {
13
if (DBG) Log.i(TAG, "matched AAR to NDEF");
14
return true;
15
}
16
}
17
//到下面应该aar包中没有对ACTION_NDEF_DISCOVERED这个action感兴趣的activity.
18
//然后就区启动aar中的第一个包含的apk
19
// Try to perform regular launch of the first AAR
20
if (aarPackages.size() > 0) {
21
String firstPackage = aarPackages.get(0);
22
PackageManager pm;
23
try {
24
UserHandle currentUser = new UserHandle(ActivityManager.getCurrentUser());
25
pm = mContext.createPackageContextAsUser("android", 0,
26
currentUser).getPackageManager();
27
} ...
28
29
Intent appLaunchIntent = pm.getLaunchIntentForPackage(firstPackage);
30
if (appLaunchIntent != null && dispatch.tryStartActivity(appLaunchIntent)) {
31
if (DBG) Log.i(TAG, "matched AAR to application launch");
32
return true;
33
}
34
// Find the package in Market: (看这架势让我们去下载呀,这么流氓哈)
35
Intent marketIntent = getAppSearchIntent(firstPackage);
36
if (marketIntent != null && dispatch.tryStartActivity(marketIntent)) {
37
if (DBG) Log.i(TAG, "matched AAR to market launch");
38
return true;
39
}
40
}
41
......
42
//当消息中没有包名的时候,就用前面设置的intent:setNdefIntent
43
//来启动activity,所以此时所有注册的activity都会受到这个action,然后你可以选择用那个启动
44
dispatch.intent.setPackage(null);
45
if (dispatch.tryStartActivity()) {
46
if (DBG) Log.i(TAG, "matched NDEF");
47
return true;
48
}
49
return false;
50
}
而tryTech()的思想是一样的,也是经过一系列判断后,通过dispatch.tryStartActivity()来启动,不过它启动
的是action为NfcAdapter.ACTION_TECH_DISCOVERED的,不再赘述。
当都不能处理的时候就调用dispatch.setTagIntent()把intent设置NfcAdapter.ACTION_TAG_DISCOVERED
用它去启动符合要求的activity,在启动失败的时候就会返回分发失败的状态.
至此完成整体Tag的读取分发系统.
2、写入Tag的简单流程
写开发时app调用framework层的对应的不同协议的Tag代表的类的接口有如下:
位于:android/frameworks/base/core/java/android/nfc/tech
有: NfcA.java、NfcB.java、NfcF.java、def.java、IsoDep.java ... 等等。
这些类都代表了指定的不同协议的Tag的实现.此处我们以android中的Ndef为例,你想要写入数据的
时候,调用Ndef类的如下接口,第三方写入的时候的过程(???具体前奏还不太清楚)
1
public void writeNdefMessage(NdefMessage msg) throws IOException, FormatException {
2
checkConnected();
3
try {
4
//tagServices 在 packages/app/Nfc中实现的
5
INfcTag tagService = mTag.getTagService();
6
......
7
int serviceHandle = mTag.getServiceHandle();
8
if (tagService.isNdef(serviceHandle)) {
9
//调用tagService的ndefWrite实现真正的写入
10
int errorCode = tagService.ndefWrite(serviceHandle, msg);
11
switch (errorCode) {
12
case ErrorCodes.SUCCESS:
13
break;
14
case ErrorCodes.ERROR_IO:
15
throw new IOException();
16
case ErrorCodes.ERROR_INVALID_PARAM:
17
throw new FormatException();
18
default:
19
// Should not happen
20
throw new IOException();
21
}
22
}
23
......
24
} catch (RemoteException e) {
25
Log.e(TAG, "NFC service dead", e);
26
}
27
}
那么我们就需要去packages/app/Nfc当中找INfcTag的具体实现了,是位于NfcService当中的内部类
final class TagService extends INfcTag.Stub调用内部方法ndefWrite
1
@Override
2
public int ndefWrite(int nativeHandle, NdefMessage msg) throws RemoteException {
3
NfcPermissions.enforceUserPermissions(mContext);
4
5
TagEndpoint tag;
6
......
7
//下面是真正的写入的地方
8
if (tag.writeNdef(msg.toByteArray())) {
9
return ErrorCodes.SUCCESS;
10
} else {
11
return ErrorCodes.ERROR_IO;
12
}
13
}
前面我们已经说过TagEndpoint是有NativeNfcTag实现的,对应的方法如下
1
private native boolean doWrite(byte[] buf);
2
@Override
3
public synchronized boolean writeNdef(byte[] buf) {
4
if (mWatchdog != null) {
5
mWatchdog.pause();
6
}
7
//可以看到去native层进行进一步的读写!
8
boolean result = doWrite(buf);//go to the native
9
if (mWatchdog != null) {
10
mWatchdog.doResume();
11
}
12
return result;
13
}
至此java层的写入流程就分析完毕了。
下面是调试的时候一次写入的Log记录一下,会先调用链接,再调用transceive,最后再写入。
1
04-21 00:37:02.032 D/zy ( 2652): Nfcervice connect
2
04-21 00:37:02.042 D/zy ( 2652): NativeNfc transceive
3
04-21 00:37:02.070 D/zy ( 2652): Nfcervice connect
4
04-21 00:37:02.094 D/zy ( 2652): Nfcervice ndefWrite
5
04-21 00:37:02.094 D/zy ( 2652): NativeNfc writeNdef