文章整理总结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

NFC源码分析之R/W工作模式相关推荐

  1. [转载]NFC源码分析之R/W工作模式

    https://blog.csdn.net/zy00000000001/article/details/71183262 文章整理总结java层,NFC读取和写入Tag的流程. 整体的时序图: 1.读 ...

  2. Spring IOC 容器源码分析 - 余下的初始化工作

    1. 简介 本篇文章是"Spring IOC 容器源码分析"系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bea ...

  3. Android源码分析—属性动画的工作原理

    转载请注明出处: http://blog.csdn.net/singwhatiwanna/article/details/17853275 前言 本文为Android动画系列的最后一篇文章,通过对源码 ...

  4. Nginx源码分析:master/worker工作流程概述

    nginx源码分析 nginx-1.11.1 参考书籍<深入理解nginx模块开发与架构解析> Nginx的master与worker工作模式 在生成环境中的Nginx启动模式基本都是以m ...

  5. 【转】ABP源码分析九:后台工作任务

    文主要说明ABP中后台工作者模块(BackgroundWorker)的实现方式,和后台工作模块(BackgroundJob).ABP通过BackgroundWorkerManager来管理Backgr ...

  6. Android属性动画赏析,Android源码分析—属性动画的工作原理

    前言 本文为Android动画系列的最后一篇文章,通过对源码的分析,能够让大家更深刻地理解属性动画的工作原理,这有助于我们更好地使用属性动画.但是,由于动画的底层实现已经深入到jni层,并且涉及到显示 ...

  7. NFC源码分析之Handover

    此处的代码为Android O的代码,本也有有一些patch的添加和修改,不过这些都不影响整个流程的理解.Handover相关的 大致可分为两种情况:直接读取带NFC的特殊设备如:带Nfc的蓝牙耳机. ...

  8. Java源码分析:深入探讨Iterator模式

    http://tech.ccidnet.com/art/3539/20060712/618391_1.html java.util包中包含了一系列重要的集合类.本文将从分析源码入手,深入研究一个集合类 ...

  9. NFC源码分析-ZGS

    Nfc的app代码位于: android/package/apps/Nfc/... 编译生成Nfc的apk和libnfc_nci_jni.so Nfc的协议栈和Hal相关的代码位于: system/n ...

最新文章

  1. 前端Vue学习之路(一)-初识Vue
  2. androidx和android的区别,【译】使用AndroidX代替Android支持库
  3. android webview 多文件上传,Android中的webview支持页面中的文件上传实例代码
  4. stm32 Bootloader设计(YModem协议)
  5. WCF绑定细节(2)——绑定,绑定元素
  6. jdk自带的Unicode转utf8工具
  7. Oracle入门(十三B)之高级查询(上)
  8. android webview远程调试
  9. http状态码 以及请求响应头相关
  10. 【超详细转】VMware 9 安装 Mac OS X 10.8 Mountain Lion 图文全程
  11. Matlab 四阶龙格库塔法求解二元常微分方程组
  12. Linux系统中解决Device eth0 does not seem to be present,delaying initialization问题
  13. 2015年8月4日工作日志--------赵鑫
  14. 打乱魔方软件_怎样打乱魔方
  15. 华为关于LINUX的认证,华为认证:华为TA128在LINUX下的简单设置
  16. 鸿蒙系统和安卓的区别在哪里,有什么不同
  17. CSS Border (边框)
  18. 杭州市民卡面试题【杭州多测师】【杭州多测师_王sir】
  19. xcode中添加新字体【ttf】
  20. 数字化时代10:从我国经济建设目标看社会产品形态的变化

热门文章

  1. macino404 || cinema 4D 基础解释 || 第一篇
  2. 手机html在哪儿,怎么定位手机位置在哪?其实很简单就这样设置就可以了
  3. HTML、JS的压缩
  4. 平均薪资28K,前端开发的涨薪史,看哭了...
  5. 修改注册表恢复IE设置(转)
  6. fftw的Windows版安装及遇到的问题
  7. 【SWAT水文模型】SWAT水文模型建立及应用第二期:土地利用数据的准备
  8. Python自动移动电驴下载完成的文件(未完)
  9. Java判断手机号归属地
  10. 嵌入式系统开发笔记48:计算圆的直径、周长和面积(Python语言)