[NFC]NFC App开发

2024-05-04 00:08
文章标签 app 开发 nfc

本文主要是介绍[NFC]NFC App开发,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

   前面描述了NFC的Tag流程和P2P流程,从实用的角度来看,我们会在介绍一下Tag和P2P APP开发的流程的一些介绍。


TAG APP开发介绍

        为了清楚的描述问题,使用GITHUB上的开源项目NfcReader作为讲解对象,如果有兴趣的,可以下载到local研究一下。


分析方法:

1. 查看AndroidManifest.xml文件,查找到Activity的入口

2. 从入口文件开始分析 


        依据AndroidManifest.xml内容,我们会进入到TagView中,默认Android SDK提供的android.nfc和android.nfc.tech两个包,APP的操作都是基于SDK暴露的接口来实现的。


        在TagView.Java的onCreate()函数中:

[java]  view plain copy
print ?
  1. @Override  
  2. protected void onCreate(Bundle savedInstanceState) {  
  3.     super.onCreate(savedInstanceState);  
  4.     setContentView(R.layout.tag_viewer);  
  5.     mTagContent = (LinearLayout) findViewById(R.id.list);  
  6.     //@Paul: APP创建的时候,分析当前APP接收到的intent信息  
  7.     //        getIntent():用于获取当前的Intent信息  
  8.     resolveIntent(getIntent());  
  9.   
  10.     //@Paul:产生提示消息的对话框,后续有提示消息时,直接更新内容  
  11.     mDialog = new AlertDialog.Builder(this).setNeutralButton("Ok"null).create();  
  12.   
  13.     //@Paul:产生NfcAdaptor,在SDK中所有对NFC的操作,都是透过NFCAdaptor来实现的  
  14.     //       NFCAdapter调用到NfcManager中的mAdaptor  
  15.     mAdapter = NfcAdapter.getDefaultAdapter(this);  
  16.     if (mAdapter == null) {  
  17.         //@Paul: 创建出错的处理  
  18.         showMessage(R.string.error, R.string.no_nfc);  
  19.         finish();  
  20.         return;  
  21.     }  
  22.   
  23.     //@Paul:创建PendingIntent,后续会在onResume中使用  
  24.     mPendingIntent = PendingIntent.getActivity(this0,  
  25.             new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);  
  26.     //@Paul:创建NdefPushMessage,用于发送消息  
  27.     mNdefPushMessage = new NdefMessage(new NdefRecord[] { newTextRecord(  
  28.             "Message from NFC Reader :-)", Locale.ENGLISH, true) });  
  29. }  

        在onCreate()函数主要是生成一些后续会用到的变量,最关键部分就是生成了mAdaptor和mPendingIntent,这两个变量在后面的地位比较重要。所有对NFC的操作,都是基于mAdaptor来实现,而mPendingIntent在Tag分发时起到了重要的作用。


        接下来将分析onResume()和onPause()函数:

[java]  view plain copy
print ?
  1.    @Override  
  2.    protected void onResume() {  
  3. //@Paul: 回到前台时,判断NFC是否enable  
  4. //        如果没有enable,则显示setting界面  
  5.        super.onResume();  
  6.        if (mAdapter != null) {  
  7.            if (!mAdapter.isEnabled()) {  
  8.                showWirelessSettingsDialog();  
  9.            }  
  10.     //@Paul: 调用类:NFCAdaptor->NFCService->NfcDispatcher  
  11.     //        最终调用NfcDispatcher.setForegroundDispatch()  
  12.            //        更新: mOverrideIntent   
  13.     //              mOverrideFilters   
  14.     //              mOverrideTechLists   
  15.            mAdapter.enableForegroundDispatch(this, mPendingIntent, nullnull);<span style="font-family: Arial, Helvetica, sans-serif;">      </span>  
  16.            //@Paul: 调用类:NFCAdaptor->NFCActivityManager  
  17.     //        NFCActivityManager.setNdefPushMessage()  
  18.            mAdapter.enableForegroundNdefPush(this, mNdefPushMessage);  
  19.        }  
  20.    }  
  21.   
  22.    @Override  
  23.    protected void onPause() {  
  24.        super.onPause();  
  25.        if (mAdapter != null) {  
  26.     //@Paul: 将onResume中设置的值都设为null  
  27.            mAdapter.disableForegroundDispatch(this);  
  28.     //@Paul: mNfcActivityManager.setNdefPushMessage(null)  
  29.         //        mNfcActivityManager.setNdefPushMessageCallback( null)  
  30.     //        mNfcActivityManager.setOnNdefPushCompleteCallback(null)  
  31.            mAdapter.disableForegroundNdefPush(this);  
  32.        }  
  33.    }  
  34.   
  35. @Override  
  36. //@Paul: 和程序的启动方式有关,多个调用希望只有一个Activity的实例存在时  
  37.    public void onNewIntent(Intent intent) {  
  38. //@Paul:务必更新当前的intent值  
  39.        setIntent(intent);  
  40. //@Paul: 此例单独实现,将收到的数据解析成NDEF Message  
  41.        resolveIntent(intent);  
  42.    }  

       关于NFC Tag流程上面几乎都有介绍到,总结一下:

        1. 创建NFCAdaptor和PendingIntnet对象

        2. 在onPause()和onResume()中调用enable和disable,将上层APP的参数设置下去。 一旦底层Driver侦测到有Tag设备进入范围,就会调用到NfcDispatcher.java中的dispatchTag(),该函数就会调用到:

[java]  view plain copy
print ?
  1. if (tryOverrides(dispatch, tag, message, overrideIntent, overrideFilters,  
  2.         overrideTechLists)) {  
  3.     return screenUnlocked ? DISPATCH_UNLOCK : DISPATCH_SUCCESS;  
  4. }  

        

        最终会调用到overrideIntent.send(mContext, Activity.RESULT_OK, intent), 此函数会将底层侦听的Tag信息发送到APP注册了enableForegroundDispatch()的app,并且上述app会进行Tag信息的解析和处理(当前例子就是进入onNewIntent()函数)。


        基本上Tag的流程就分析完成了。


P2P APP开发介绍

        其实在Tag的APP介绍中,隐含了部分P2P的处理,比如代码中enableForegroundNdefPush()的调用和处理。实际上调用enableForegroundNdefPush()就会进入到下面部分setNdefPushMessage()。


        此部分将重点介绍一下,一旦调用了setNdefPushMessage(),  setNdefPushMessageCallback(),  setOnNdefPushCompleteCallback()后,会影响到底层哪些模块。


        先从setNdefPushMessage()开始,在此函数中会依次将上层APP要传递的消息以及回调函数信息更新到framework层,最终这些信息会在prepareMessageToSend()中得到处理,并组成待发送数据。

[java]  view plain copy
print ?
  1. public void setNdefPushMessage(Activity activity, NdefMessage message, int flags) {  
  2.     boolean isResumed;  
  3.     synchronized (NfcActivityManager.this) {  
  4.         //@Paul: 将当前APP设置的信息存储在NfcActivityState  
  5.         //       后续会NFCActivityManager/createBeamShareData()中使用到此消息  
  6.         NfcActivityState state = getActivityState(activity);  
  7.         state.ndefMessage = message;  
  8.         state.flags = flags;  
  9.         isResumed = state.resumed;  
  10.     }  
  11.     if (isResumed) {  
  12.         //@Paul: 一般来说,在此Activity中还会定义createBeamShareData(),前提是要支持Android Beam  
  13.         requestNfcServiceCallback();  
  14.     }  
  15. }  
  16.   
  17. void requestNfcServiceCallback() {  
  18.     try {  
  19.         //@Paul: 调用NFCService中的setAppCallback中  
  20.         NfcAdapter.sService.setAppCallback(this);  
  21.     } catch (RemoteException e) {  
  22.         mAdapter.attemptDeadServiceRecovery(e);  
  23.     }  
  24. }  
  25.   
  26. @Override  
  27. public void setAppCallback(IAppCallback callback) {  
  28.     NfcPermissions.enforceUserPermissions(mContext);  
  29.   
  30.     UserInfo userInfo = mUserManager.getUserInfo(UserHandle.getCallingUserId());  
  31.     if(!userInfo.isManagedProfile()  
  32.             && !mUserManager.hasUserRestriction(  
  33.                     UserManager.DISALLOW_OUTGOING_BEAM, userInfo.getUserHandle())) {  
  34.         //@Paul: 此函数是关键,将更新mCallbackNdef的值,如果没有更新时,此值为null  
  35.         //       一旦此值不为null,就会调用mCallbackNdef.createBeamShareData()和mCallbackNdef.onNdefPushComplete()  
  36.         mP2pLinkManager.setNdefCallback(callback, Binder.getCallingUid());  
  37.     } else if (DBG) {  
  38.         Log.d(TAG, "Disabling default Beam behavior");  
  39.     }  
  40. }  


        需要注意的是,如果需要阻止系统发送默认的NDEF消息,那可以在AndroidManifest.xml中添加:

<meta-data android:name="android.nfc.disable_beam_defaulte" android:value="true"/>


        下面开始介绍setNdefPushMessageCallback()函数,此函数的作用就是设置产生Beam数据的回调,代码分析如下:

[java]  view plain copy
print ?
  1. public void setNdefPushMessageCallback(Activity activity,  
  2.         NfcAdapter.CreateNdefMessageCallback callback, int flags) {  
  3.     boolean isResumed;  
  4.     synchronized (NfcActivityManager.this) {  
  5.         NfcActivityState state = getActivityState(activity);  
  6.         //@Paul: 更新NfcActivityState中的ndefMessageCallback  
  7.         state.ndefMessageCallback = callback;  
  8.         state.flags = flags;  
  9.         isResumed = state.resumed;  
  10.     }  
  11.     if (isResumed) {  
  12.         requestNfcServiceCallback();  
  13.     }  
  14. }  

        其中ndefMessageCallback变量会最终在下面的函数中被调用到:

[java]  view plain copy
print ?
  1. void prepareMessageToSend(boolean generatePlayLink) {  
  2.     synchronized (P2pLinkManager.this) {  
  3.         mMessageToSend = null;  
  4.         mUrisToSend = null;  
  5.         if (!mIsSendEnabled) {  
  6.             return;  
  7.         }  
  8.   
  9.         List<Integer> foregroundUids = mForegroundUtils.getForegroundUids();  
  10.         if (foregroundUids.isEmpty()) {  
  11.             Log.e(TAG, "Could not determine foreground UID.");  
  12.             return;  
  13.         }  
  14.   
  15.         //@Paul: 如果定义了callback  
  16.         if (mCallbackNdef != null) {  
  17.             if (foregroundUids.contains(mNdefCallbackUid)) {  
  18.                 try {  
  19.                     //@Paul: 调用callback对应的createBeamShareData()函数  
  20.                     BeamShareData shareData = mCallbackNdef.createBeamShareData();  
  21.                     mMessageToSend = shareData.ndefMessage;  
  22.                     mUrisToSend = shareData.uris;  
  23.                     mSendFlags = shareData.flags;  
  24.                     return;  
  25.                 } catch (Exception e) {  
  26.                     Log.e(TAG, "Failed NDEF callback: " + e.getMessage());  
  27.                 }  
  28.             } else {  
  29.                 ...  
  30.             }  
  31.         }  
  32.   
  33.         ...  
  34.     }  
  35. }  

        上面createBeamShareData()需要在APP中进行定义。 


        补充一下,setNdefPushMessage()和setNdefPushMessageCallback()在系统同时被调用时,setNdefPushMessageCallback()的优先级较高,系统会优先选择callback产生NDEF Message; 这两个API的差异是:setNdefPushMessage()发送的数据为固定数据,而setNdefPushMessageCallback()则是APP可以更新的。


     

这篇关于[NFC]NFC App开发的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/957947

相关文章

Python实例题之pygame开发打飞机游戏实例代码

《Python实例题之pygame开发打飞机游戏实例代码》对于python的学习者,能够写出一个飞机大战的程序代码,是不是感觉到非常的开心,:本文主要介绍Python实例题之pygame开发打飞机... 目录题目pygame-aircraft-game使用 Pygame 开发的打飞机游戏脚本代码解释初始化部

使用Python开发一个现代化屏幕取色器

《使用Python开发一个现代化屏幕取色器》在UI设计、网页开发等场景中,颜色拾取是高频需求,:本文主要介绍如何使用Python开发一个现代化屏幕取色器,有需要的小伙伴可以参考一下... 目录一、项目概述二、核心功能解析2.1 实时颜色追踪2.2 智能颜色显示三、效果展示四、实现步骤详解4.1 环境配置4.

Python使用smtplib库开发一个邮件自动发送工具

《Python使用smtplib库开发一个邮件自动发送工具》在现代软件开发中,自动化邮件发送是一个非常实用的功能,无论是系统通知、营销邮件、还是日常工作报告,Python的smtplib库都能帮助我们... 目录代码实现与知识点解析1. 导入必要的库2. 配置邮件服务器参数3. 创建邮件发送类4. 实现邮件

基于Python开发一个有趣的工作时长计算器

《基于Python开发一个有趣的工作时长计算器》随着远程办公和弹性工作制的兴起,个人及团队对于工作时长的准确统计需求日益增长,本文将使用Python和PyQt5打造一个工作时长计算器,感兴趣的小伙伴可... 目录概述功能介绍界面展示php软件使用步骤说明代码详解1.窗口初始化与布局2.工作时长计算核心逻辑3

python web 开发之Flask中间件与请求处理钩子的最佳实践

《pythonweb开发之Flask中间件与请求处理钩子的最佳实践》Flask作为轻量级Web框架,提供了灵活的请求处理机制,中间件和请求钩子允许开发者在请求处理的不同阶段插入自定义逻辑,实现诸如... 目录Flask中间件与请求处理钩子完全指南1. 引言2. 请求处理生命周期概述3. 请求钩子详解3.1

如何基于Python开发一个微信自动化工具

《如何基于Python开发一个微信自动化工具》在当今数字化办公场景中,自动化工具已成为提升工作效率的利器,本文将深入剖析一个基于Python的微信自动化工具开发全过程,有需要的小伙伴可以了解下... 目录概述功能全景1. 核心功能模块2. 特色功能效果展示1. 主界面概览2. 定时任务配置3. 操作日志演示

JavaScript实战:智能密码生成器开发指南

本文通过JavaScript实战开发智能密码生成器,详解如何运用crypto.getRandomValues实现加密级随机密码生成,包含多字符组合、安全强度可视化、易混淆字符排除等企业级功能。学习密码强度检测算法与信息熵计算原理,获取可直接嵌入项目的完整代码,提升Web应用的安全开发能力 目录

一文教你如何解决Python开发总是import出错的问题

《一文教你如何解决Python开发总是import出错的问题》经常朋友碰到Python开发的过程中import包报错的问题,所以本文将和大家介绍一下可编辑安装(EditableInstall)模式,可... 目录摘要1. 可编辑安装(Editable Install)模式到底在解决什么问题?2. 原理3.

Python+PyQt5开发一个Windows电脑启动项管理神器

《Python+PyQt5开发一个Windows电脑启动项管理神器》:本文主要介绍如何使用PyQt5开发一款颜值与功能并存的Windows启动项管理工具,不仅能查看/删除现有启动项,还能智能添加新... 目录开篇:为什么我们需要启动项管理工具功能全景图核心技术解析1. Windows注册表操作2. 启动文件

使用Python开发Markdown兼容公式格式转换工具

《使用Python开发Markdown兼容公式格式转换工具》在技术写作中我们经常遇到公式格式问题,例如MathML无法显示,LaTeX格式错乱等,所以本文我们将使用Python开发Markdown兼容... 目录一、工具背景二、环境配置(Windows 10/11)1. 创建conda环境2. 获取XSLT