本文主要是介绍[NFC]Tag设备响应流程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
接上部分的分析,当前系统已经进入到applyRouting()阶段,后续应该是需要一直去监听当前是否有NFC设备进入通讯范围。如果有适合的NFC设备,则底层会先进行沟通,并将消息通知给上层。
进入NFC设备发现流程
下面从applyRouting()函数开始分析,可以参考系统注释:
- void applyRouting(boolean force) {
- synchronized (this) {
- //@paul: 如果NFC没有打开或者已经关闭,则直接发挥
- if (!isNfcEnabledOrShuttingDown()) {
- return;
- }
- ...
- if (mInProvisionMode) {
- mInProvisionMode = Settings.Secure.getInt(mContentResolver,
- Settings.Global.DEVICE_PROVISIONED, 0) == 0;
- if (!mInProvisionMode) {
- //@paul: 原生的Android里面Provision只做了一件事,就是写入一个DEVICE_PROVISIONED标记。
- //@paul: 不过这个标记作用很大,这个标记只会在系统全新升级(双清)的时候写入一次,代表了Android系统升级准备完成,可以正常工作。
- mNfcDispatcher.disableProvisioningMode();
- mHandoverManager.setEnabled(true);
- }
- }
- //@paul: 如果有tag正在通讯时,delay一段时间再更新参数
- // Special case: if we're transitioning to unlocked state while
- // still talking to a tag, postpone re-configuration.
- if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && isTagPresent()) {
- Log.d(TAG, "Not updating discovery parameters, tag connected.");
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RESUME_POLLING),
- APPLY_ROUTING_RETRY_TIMEOUT_MS);
- return;
- }
- try {
- watchDog.start();
- //@paul: 依据前面初始化的参数来更新NfcDiscoveryParameters
- // Compute new polling parameters
- NfcDiscoveryParameters newParams = computeDiscoveryParameters(mScreenState);
- if (force || !newParams.equals(mCurrentDiscoveryParameters)) {
- //@paul: 判断条件为:mTechMask != 0 || mEnableHostRouting
- //@paul:mTechMask一般不为0,mEnableHostRouting一般为false
- if (newParams.shouldEnableDiscovery()) {
- boolean shouldRestart = mCurrentDiscoveryParameters.shouldEnableDiscovery();
- //@paul:系统一般会进入enableDiscovery()
- mDeviceHost.enableDiscovery(newParams, shouldRestart);
- } else {
- mDeviceHost.disableDiscovery();
- }
- mCurrentDiscoveryParameters = newParams;
- } else {
- Log.d(TAG, "Discovery configuration equal, not updating.");
- }
- } finally {
- watchDog.cancel();
- }
- }
- }
由于系统调用到enableDiscovery()函数,此函数不论是nxp还是nci,都会调用到native函数doEnableDiscovery(),继续追踪此函数(后续都已NXP为例),最终调用到com_android_nfc_NativeNfcManager.cpp中的:
- {"doEnableDiscovery", "(IZZZ)V",
- (void *)com_android_nfc_NfcManager_enableDiscovery},
继续追踪com_android_nfc_NfcManager_enableDiscovery():
- static void com_android_nfc_NfcManager_enableDiscovery(JNIEnv *e, jobject o, jint modes,
- jboolean, jboolean reader_mode, jboolean restart)
- {
- ...
- /* Register callback for remote device notifications.
- * Must re-register every time we turn on discovery, since other operations
- * (such as opening the Secure Element) can change the remote device
- * notification callback*/
- //@paul: 注册侦听到NFC设备时的回调函数,后续的流程从此开始
- REENTRANCE_LOCK();
- ret = phLibNfc_RemoteDev_NtfRegister(&nat->registry_info, nfc_jni_Discovery_notification_callback, (void *)nat);
- REENTRANCE_UNLOCK();
- ...
- //@paul: 启动discovery流程
- nfc_jni_start_discovery_locked(nat, restart);
- clean_and_return:
- CONCURRENCY_UNLOCK();
- }
此处的两个函数nfc_jni_start_discovery_locked()和nfc_jni_Discovery_notification_callback()都需要在深入一点,一个一个的看:
- static void nfc_jni_start_discovery_locked(struct nfc_jni_native_data *nat, bool resume)
- {
- ...
- configure:
- /* Start Polling loop */
- TRACE("****** Start NFC Discovery ******");
- REENTRANCE_LOCK();
- //@paul: nfc_jni_discover_callback()是discover后消息notify的开始
- ret = phLibNfc_Mgt_ConfigureDiscovery(resume ? NFC_DISCOVERY_RESUME : NFC_DISCOVERY_CONFIG,
- nat->discovery_cfg, nfc_jni_discover_callback, (void *)&cb_data);
- REENTRANCE_UNLOCK();
- ...
- clean_and_return:
- nfc_cb_data_deinit(&cb_data);
- }
一旦上面进入了nfc_jni_discover_callback(),后续就会进入nfc_jni_Discovery_notification_callback(),此函数就会把底层看到的信息开始一层一层的notify:
- static void nfc_jni_Discovery_notification_callback(void *pContext,
- phLibNfc_RemoteDevList_t *psRemoteDevList,
- uint8_t uNofRemoteDev, NFCSTATUS status)
- {
- ...
- if(status == NFCSTATUS_DESELECTED)
- {
- LOG_CALLBACK("nfc_jni_Discovery_notification_callback: Target deselected", status);
- /* Notify manager that a target was deselected */
- //@paul: 执行cached_NfcManager_notifyTargetDeselected对应的java函数
- e->CallVoidMethod(nat->manager, cached_NfcManager_notifyTargetDeselected);
- if(e->ExceptionCheck())
- {
- ALOGE("Exception occurred");
- kill_client(nat);
- }
- }
- else
- {
- ...
- if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
- || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target))
- {
- ...
- /* Set P2P Target mode */
- jfieldID f = e->GetFieldID(tag_cls.get(), "mMode", "I");
- if(remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
- {
- ALOGD("Discovered P2P Initiator");
- e->SetIntField(tag.get(), f, (jint)MODE_P2P_INITIATOR);
- }
- else
- {
- ALOGD("Discovered P2P Target");
- e->SetIntField(tag.get(), f, (jint)MODE_P2P_TARGET);
- }
- ...
- }
- else
- {
- ...
- /* New tag instance */
- ...
- /* Set tag UID */
- ...
- /* Generate technology list */
- ...
- }
- ...
- /* Notify the service */
- if((remDevInfo->RemDevType == phNfc_eNfcIP1_Initiator)
- || (remDevInfo->RemDevType == phNfc_eNfcIP1_Target))
- {
- /* Store the handle of the P2P device */
- hLlcpHandle = remDevHandle;
- /* Notify manager that new a P2P device was found */
- //@paul: 侦测到P2P设备进入范围,调用JNI层对应的API,最终call到JAVA层API
- e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag.get());
- if(e->ExceptionCheck())
- {
- ALOGE("Exception occurred");
- kill_client(nat);
- }
- }
- else
- {
- /* Notify manager that new a tag was found */
- //@paul:侦测到Tag设备进入范围,
- e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag.get());
- if(e->ExceptionCheck())
- {
- ALOGE("Exception occurred");
- kill_client(nat);
- }
- }
- }
- }
所以Tag的真正开始时在执行下列函数后:
- e->CallVoidMethod(nat->manager, cached_NfcManager_notifyNdefMessageListeners, tag.get());
最终调用到JNI层的notifyNdefMessageListeners(),对应的定义在:
- private void notifyNdefMessageListeners(NativeNfcTag tag) {
- mListener.onRemoteEndpointDiscovered(tag);
- }
为后文作准备,P2P设备的Framework开始时在执行下列函数:
- e->CallVoidMethod(nat->manager, cached_NfcManager_notifyLlcpLinkActivation, tag.get());
最终调用到JNI层的notifyLlcpLinkActivation(),对应的定义在:
- private void notifyLlcpLinkActivation(NativeP2pDevice device) {
- mListener.onLlcpLinkActivated(device);
- }
Tag设备发现framework流程
下面开始分析Tag的Framework的流程:我们的分析会从mListener.onRemoteEndpointDiscovered(tag)开始:
- @Override
- public void onRemoteEndpointDiscovered(TagEndpoint tag) {
- sendMessage(NfcService.MSG_NDEF_TAG, tag);
- }
其中发送的消息MSG_NDEF_TAG会进入到NfcService.java的handleMessage(),其中处理MSG_NDEF_TAG的流程如下:
- case MSG_NDEF_TAG:
- if (DBG) Log.d(TAG, "Tag detected, notifying applications");
- ...
- //@paul: 如果是read mode
- if (readerParams != null) {
- presenceCheckDelay = readerParams.presenceCheckDelay;
- //@paul: 如果设置不检查能否转成NDEF的标记
- if ((readerParams.flags & NfcAdapter.FLAG_READER_SKIP_NDEF_CHECK) != 0) {
- if (DBG) Log.d(TAG, "Skipping NDEF detection in reader mode");
- //@paul: 判断tag是否还在范围内
- tag.startPresenceChecking(presenceCheckDelay, callback);
- //@paul: 将侦测的tag进行分发
- dispatchTagEndpoint(tag, readerParams);
- break;
- }
- }
- boolean playSound = readerParams == null ||
- (readerParams.flags & NfcAdapter.FLAG_READER_NO_PLATFORM_SOUNDS) == 0;
- if (mScreenState == ScreenStateHelper.SCREEN_STATE_ON_UNLOCKED && playSound) {
- //paul: 播放开始声音
- playSound(SOUND_START);
- }
- if (tag.getConnectedTechnology() == TagTechnology.NFC_BARCODE) {
- // When these tags start containing NDEF, they will require
- // the stack to deal with them in a different way, since
- // they are activated only really shortly.
- // For now, don't consider NDEF on these.
- if (DBG) Log.d(TAG, "Skipping NDEF detection for NFC Barcode");
- //@paul: 如果是Barcode,直接进行tag的分发
- tag.startPresenceChecking(presenceCheckDelay, callback);
- dispatchTagEndpoint(tag, readerParams);
- break;
- }
- //@paul: 依据底层格式,进行NDEF的转换
- NdefMessage ndefMsg = tag.findAndReadNdef();
- if (ndefMsg != null) {
- //@paul: NDEF转换成功后,进行Tag的分发
- tag.startPresenceChecking(presenceCheckDelay, callback);
- dispatchTagEndpoint(tag, readerParams);
- } else {
- //@paul: 无法转换时,先进行底层的连接后(物理层先重连),将消息分发
- if (tag.reconnect()) {
- tag.startPresenceChecking(presenceCheckDelay, callback);
- dispatchTagEndpoint(tag, readerParams);
- } else {
- tag.disconnect();
- playSound(SOUND_ERROR);
- }
- }
- break;
其中比较关键的函数有两个:
findAndReadNdef()
dispatchTagEndpoint()
findAndReadNdef()是和芯片强相关的,其目的是依据芯片的支持能力,将读到的Tag中的内容转换成NDEF格式的数据. 不同芯片其支持的能力存在差异,此部分的code也是存在差异,针对NXP芯片简单分析如下:
- @Override
- public NdefMessage findAndReadNdef() {
- ...
- for (int techIndex = 0; techIndex < technologies.length; techIndex++) {
- ...
- //@paul: 判断connectedHandle与当前Index对应的handle的关系,并更新状态,
- status = connectWithStatus(technologies[techIndex]);
- ...
- // Check if this type is NDEF formatable
- if (!foundFormattable) {
- //@paul: 依据芯片特性判断哪些tag是可以转成NDEF格式
- if (isNdefFormatable()) {
- //@paul: 更新对应的handle,handle用于后续的操作
- foundFormattable = true;
- formattableHandle = getConnectedHandle();
- formattableLibNfcType = getConnectedLibNfcType();
- // We'll only add formattable tech if no ndef is
- // found - this is because libNFC refuses to format
- // an already NDEF formatted tag.
- }
- reconnect();
- }
- ...
- status = checkNdefWithStatus(ndefinfo);
- ...
- //@paul: 读取tag上的数据
- byte[] buff = readNdef();
- if (buff != null) {
- try {
- //@paul: 将数据转换成NDEF格式
- ndefMsg = new NdefMessage(buff);
- //@paul: 更新对应Tag的信息
- addNdefTechnology(ndefMsg,
- getConnectedHandle(),
- getConnectedLibNfcType(),
- getConnectedTechnology(),
- supportedNdefLength, cardState);
- reconnect();
- } catch (FormatException e) {
- // Create an intent anyway, without NDEF messages
- generateEmptyNdef = true;
- }
- } else {
- generateEmptyNdef = true;
- }
- ...
- }
- if (ndefMsg == null && foundFormattable) {
- // Tag is not NDEF yet, and found a formattable target,
- // so add formattable tech to tech list.
- addNdefFormatableTechnology(
- formattableHandle,
- formattableLibNfcType);
- }
- return ndefMsg;
- }
Tag消息分发流程
上述执行完成后,理论上会进入Tag的Dispatch流程,中间的流程省略,我们直接进入mNfcDispatcher.dispatchTag(tag)函数的分析,这才是tag分发的终极形式,直接看代码吧:
- /** Returns:
- * <ul>
- * <li /> DISPATCH_SUCCESS if dispatched to an activity,
- * <li /> DISPATCH_FAIL if no activities were found to dispatch to,
- * <li /> DISPATCH_UNLOCK if the tag was used to unlock the device
- * </ul>
- */
- public int dispatchTag(Tag tag) {
- PendingIntent overrideIntent;
- IntentFilter[] overrideFilters;
- String[][] overrideTechLists;
- boolean provisioningOnly;
- //@paul: 如果上层APP定义了下列值,就会在这里进行更新
- synchronized (this) {
- overrideFilters = mOverrideFilters;
- overrideIntent = mOverrideIntent;
- overrideTechLists = mOverrideTechLists;
- provisioningOnly = mProvisioningOnly;
- }
- //@paul: Tag在screen on 且lock的情况下,需要尝试unlock,否则如法处理
- boolean screenUnlocked = false;
- if (!provisioningOnly &&
- mScreenStateHelper.checkScreenState() == ScreenStateHelper.SCREEN_STATE_ON_LOCKED) {
- screenUnlocked = handleNfcUnlock(tag);
- if (!screenUnlocked) {
- return DISPATCH_FAIL;
- }
- }
- NdefMessage message = null;
- //@paul: 将Tag解析成NDEF格式数据,并读取内容
- Ndef ndef = Ndef.get(tag);
- if (ndef != null) {
- message = ndef.getCachedNdefMessage();
- }
- if (DBG) Log.d(TAG, "dispatch tag: " + tag.toString() + " message: " + message);
- DispatchInfo dispatch = new DispatchInfo(mContext, tag, message);
- //@paul: 和APP相关,暂时没有研究
- resumeAppSwitches();
- //@paul: 如果上层APP有定义前台分发机制,则会调用到PendingIntent.send()功能,实现前台分发机制
- if (tryOverrides(dispatch, tag, message, overrideIntent, overrideFilters,
- overrideTechLists)) {
- return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
- }
- //@paul: 判断NDEF消息是否是handover格式
- if (mHandoverManager.tryHandover(message)) {
- if (DBG) Log.i(TAG, "matched BT HANDOVER");
- return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
- }
- //@paul: 判断NDEF消息是否是WifiConfiguration格式
- if (NfcWifiProtectedSetup.tryNfcWifiSetup(ndef, mContext)) {
- if (DBG) Log.i(TAG, "matched NFC WPS TOKEN");
- return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
- }
- //@paul: 将消息发送给对ACTION_NDEF_DISCOVERED感兴趣的APP处理
- if (tryNdef(dispatch, message, provisioningOnly)) {
- return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;
- }
- if (screenUnlocked) {
- // We only allow NDEF-based mimeType matching in case of an unlock
- return DISPATCH_UNLOCK;
- }
- if (provisioningOnly) {
- // We only allow NDEF-based mimeType matching
- return DISPATCH_FAIL;
- }
- // Only allow NDEF-based mimeType matching for unlock tags
- //@paul: <span style="font-family: Arial, Helvetica, sans-serif;">将消息发送给对</span>ACTION_TECH_DISCOVERED感兴趣的APP处理
- if (tryTech(dispatch, tag)) {
- return DISPATCH_SUCCESS;
- }
- //@paul: 更新Intent为ACTION_TAG_DISCOVERED
- dispatch.setTagIntent();
- //@paul: 将消息发送给对ACTION_TAG_DISCOVERED感兴趣的APP处理
- if (dispatch.tryStartActivity()) {
- if (DBG) Log.i(TAG, "matched TAG");
- return DISPATCH_SUCCESS;
- }
- if (DBG) Log.i(TAG, "no match");
- return DISPATCH_FAIL;
- }
下面分别介绍tryHandover(),tryNfcWifiSetup(),tryNdef(),tryTech().
首先看看tryHandover(),此函数主要做BlueTooth的handover,当然如果要做wifi的handover,从技术上看是完全没有问题的.
- public boolean tryHandover(NdefMessage m) {
- ...
- BluetoothHandoverData handover = parseBluetooth(m);
- ...
- synchronized (mLock) {
- ...
- <span style="white-space:pre"> </span>//@paul: 发送MSG_PERIPHERAL_HANDOVER消息,在HandleMessage中进行处理
- Message msg = Message.obtain(null, HandoverService.MSG_PERIPHERAL_HANDOVER, 0, 0);
- Bundle headsetData = new Bundle();
- headsetData.putParcelable(HandoverService.EXTRA_PERIPHERAL_DEVICE, handover.device);
- headsetData.putString(HandoverService.EXTRA_PERIPHERAL_NAME, handover.name);
- headsetData.putInt(HandoverService.EXTRA_PERIPHERAL_TRANSPORT, handover.transport);
- msg.setData(headsetData);
- return sendOrQueueMessageLocked(msg);
- }
- }
比较重要的就是parseBluetooth()和最后的sendOrQueueMessageLocked()函数。其中parseBluetooth逻辑比较简单,就是按照Spec的要求,把NDEF数据一个字节一个字节的解析出来,存放在对应的结构体中。sendOrQueueMessageLocked则是将BT的信息发送给上述完整的代码分析如下:
- BluetoothHandoverData parseBluetooth(NdefMessage m) {
- ...
- // Check for BT OOB record
- if (r.getTnf() == NdefRecord.TNF_MIME_MEDIA && Arrays.equals(r.getType(), TYPE_BT_OOB)) {
- return parseBtOob(ByteBuffer.wrap(r.getPayload()));
- }
- // Check for BLE OOB record
- if (r.getTnf() == NdefRecord.TNF_MIME_MEDIA && Arrays.equals(r.getType(), TYPE_BLE_OOB)) {
- return parseBleOob(ByteBuffer.wrap(r.getPayload()));
- }
- // Check for Handover Select, followed by a BT OOB record
- if (tnf == NdefRecord.TNF_WELL_KNOWN &&
- Arrays.equals(type, NdefRecord.RTD_HANDOVER_SELECT)) {
- return parseBluetoothHandoverSelect(m);
- }
- // Check for Nokia BT record, found on some Nokia BH-505 Headsets
- if (tnf == NdefRecord.TNF_EXTERNAL_TYPE && Arrays.equals(type, TYPE_NOKIA)) {
- return parseNokia(ByteBuffer.wrap(r.getPayload()));
- }
- return null;
- }
- public boolean sendOrQueueMessageLocked(Message msg) {
- if (!mBound || mService == null) {
- // Need to start service, let us know if we can queue the message
- //@paul: 首先bind Service,成功后会调用onServiceConnected()
- if (!bindServiceIfNeededLocked()) {
- Log.e(TAG, "Could not start service");
- return false;
- }
- // Queue the message to send when the service is bound
- //@paul: 先将消息放在缓存队列中
- mPendingServiceMessages.add(msg);
- } else {
- try {
- //@paul: 已经绑定后,则直接诶发送消息
- mService.send(msg);
- } catch (RemoteException e) {
- Log.e(TAG, "Could not connect to handover service");
- return false;
- }
- }
- return true;
- }
- public void onServiceConnected(ComponentName name, IBinder service) {
- synchronized (mLock) {
- ...
- try {
- //@paul: 直接发送消息
- mService.send(msg);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to register client");
- }
- // Send all queued messages
- while (!mPendingServiceMessages.isEmpty()) {
- //@paul: 如果mPendingServiceMessages有数据是,会一直尝试把pending的数据发送完成
- msg = mPendingServiceMessages.remove(0);
- try {
- mService.send(msg);
- } catch (RemoteException e) {
- Log.e(TAG, "Failed to send queued message to service");
- }
- }
- }
- }
前文提到发送了MSG_PERIPHERAL_HANDOVER,最终进入doPeripheralHandover()函数,目前只是分析到BT流程启动,后续建立连接部分暂不分析了。
- void doPeripheralHandover(Message msg) {
- Bundle msgData = msg.getData();
- BluetoothDevice device = msgData.getParcelable(EXTRA_PERIPHERAL_DEVICE);
- String name = msgData.getString(EXTRA_PERIPHERAL_NAME);
- int transport = msgData.getInt(EXTRA_PERIPHERAL_TRANSPORT);
- //@paul: 如果存在mBluetoothPeripheralHandover,表明有handover正在进行
- if (mBluetoothPeripheralHandover != null) {
- Log.d(TAG, "Ignoring pairing request, existing handover in progress.");
- return;
- }
- //@paul: mBluetoothPeripheralHandover
- mBluetoothPeripheralHandover = new BluetoothPeripheralHandover(HandoverService.this,
- device, name, transport, HandoverService.this);
- // TODO: figure out a way to disable polling without deactivating current target
- if (transport == BluetoothDevice.TRANSPORT_LE) {
- mHandler.sendMessageDelayed(
- mHandler.obtainMessage(MSG_PAUSE_POLLING), PAUSE_DELAY_MILLIS);
- }
- //@paul: 如果Bluetooth有启动,则执行对应的start函数
- if (mBluetoothAdapter.isEnabled()) {
- if (!mBluetoothPeripheralHandover.start()) {
- //@paul: Handover成功后,NFC继续polling
- mNfcAdapter.resumePolling();
- }
- } else {
- if (!enableBluetooth()) {
- Log.e(TAG, "Error enabling Bluetooth.");
- mBluetoothPeripheralHandover = null;
- }
- }
- }
- //@paul:接上述start函数
- public boolean start() {
- ...
- //paul: 目前只关注此函数
- nextStep();
- return true;
- }
- //@paul: 进入对应的状态机,启动BT连接
- void nextStep() {
- if (mAction == ACTION_INIT) {
- nextStepInit();
- } else if (mAction == ACTION_CONNECT) {
- nextStepConnect();
- } else {
- nextStepDisconnect();
- }
- }
分析完Handover,可能已经觉得有点累了,那我们来个简单的,看看tryNfcWifiSetup(),其实这部分和BT的原理基本类似,就是透过NFC拿到WIFI相关的credential,然后利用credential简历WIFI连接,实现Handover的目的。
- public static boolean tryNfcWifiSetup(Ndef ndef, Context context) {
- ...
- //@paul: 解析得到Wifi相关的credential数据
- final WifiConfiguration wifiConfiguration = parse(cachedNdefMessage);
- if (wifiConfiguration != null &&!UserManager.get(context).hasUserRestriction(
- UserManager.DISALLOW_CONFIG_WIFI, UserHandle.CURRENT)) {
- Intent configureNetworkIntent = new Intent()
- .putExtra(EXTRA_WIFI_CONFIG, wifiConfiguration)
- .setClass(context, ConfirmConnectToWifiNetworkActivity.class)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- //@paul: 将wifi数据放在intent中,然后以设置的参数启动wifi相关的连接
- context.startActivityAsUser(configureNetworkIntent, UserHandle.CURRENT);
- return true;
- }
- return false;
- }
接下来就是tryNdef()和tryTech()的分析,其实此部分的流程是前面提到的ACTION_TAG_DISCOVERED的流程是类似,主要是分两步:
1. 设置对应的intent为:ACTION_NDEF_DISCOVERED/ACTION_TECH_DISCOVERED
2. 以上述intent启动相关的activity. 只不过会加入AAR消息的检查,关于AAR的说明可以自行查找。简单的说明如下:
- 在Android4.0(API Level 14)中引入的Android应用程序记录(AAR),提供了较强的在扫描到NFC标签时,启动应用程序的确定性。AAR有嵌入到NDEF记录内部的应用程序的包名。你能够把一个AAR添加到你的NDEF消息的任何记录中,因为Android会针对AAR来搜索整个NDEF消息。如果它找到一个AAR,它就会基于AAR内部的包名来启动应用程序。如果该应用程序不在当前的设备上,会启动Google Play来下载对应的应用程序。
- 如果你想要防止其他的应用对相同的Intent的过滤并潜在的处理你部署的特定的NFC标签,那么AAR是有用的。AAR仅在应用程序级被支持,因为包名的约束,并不能在Activity级别来过滤Intent。如果你想要在Activity级处理Intent,请使用Intent过滤器。
以上基本就介绍完Tag的整体处理流程。代码流程稍微有点多,建议代码分几次看,以免遗忘。
后续会在介绍一下NFC P2P设备相互发现的流程。由于P2P的应用比较多,介绍的篇幅也会相对较多
这篇关于[NFC]Tag设备响应流程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!