当前位置: 首页 > ops >正文

安卓后台常驻读取NFC

正常的我们在安卓上使用NFC是调用nfcAdapter.enableForegroundDispatch然后还在这个界面的时候放上nfc卡后系统就会将nfc的信息通过pendingIntent发送出来,现在有一个这样的需求,需要常驻后台发送信息,也就是即使退出应用,这个nfc消息也能被应用接收到。

分析源码不能接收到的原因是,在enableForegroundDispatch后会注册一个名为mForegroundDispatchListener这个的回调,如果被调用了则会调用disableForegroundDispatchInternal这个方法继续调用setForegroundDispatch置空回调导致应用无法接受到nfc消息

    OnActivityPausedListener mForegroundDispatchListener = new OnActivityPausedListener() {@Overridepublic void onPaused(Activity activity) {disableForegroundDispatchInternal(activity, true);}};void disableForegroundDispatchInternal(Activity activity, boolean force) {try {sService.setForegroundDispatch(null, null, null);if (!force && !activity.isResumed()) {throw new IllegalStateException("You must disable foreground dispatching " +"while your activity is still resumed");}} catch (RemoteException e) {attemptDeadServiceRecovery(e);}}

这个回调是通过以下的方式注册上去的

            ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,mForegroundDispatchListener);

这个回调 会接监听应用的状态,如果这个应用是退出界面的状态,那么这个就会被这个接收到,然后设置了一个标志位,所以根据这个流程,我们只需要让应用的生命周期无法在paused的时候回调这个方法即可,所以我们提前反注册这个回调,就会破坏这个流程,让系统认为这个应用一直在前台回调nfc卡的信息,

那么我们就使用以下方法,大概流程是通过反射把mForegroundDispatchListener对象取出来,然后继续反射ActivityThread.currentActivityThread().unregisterOnActivityPausedListener这个方法反注册这个回调,以下是代码

            nfcAdapter = NfcAdapter.getDefaultAdapter(this);PendingIntent pendingIntent = PendingIntent.getService(this,0,new Intent(this,NfcService.class),0);nfcAdapter.enableForegroundDispatch(this,pendingIntent,null,null);Class<?> cNfcAdapter = nfcAdapter.getClass();Field[] fields = cNfcAdapter.getDeclaredFields();Field fForegroundDispatchListener = null;for (Field field : fields) {Log.i("nfcinvoke","field name " + field.getName());if(field.getName().equalsIgnoreCase("mForegroundDispatchListener")){fForegroundDispatchListener = field;}}fForegroundDispatchListener.setAccessible(true);try {Class<?> cActivityThread = Class.forName("android.app.ActivityThread");Method mCurrentActivityThread = cActivityThread.getMethod("currentActivityThread");mCurrentActivityThread.setAccessible(true);Object activityThread = mCurrentActivityThread.invoke(null);Method[] methods = activityThread.getClass().getMethods();Method mUnregisterOnActivityPausedListener = null;for (Method method : methods) {Log.i("wubin","method name 1111 " + method.getName());if(method.getName().equalsIgnoreCase("unregisterOnActivityPausedListener")){mUnregisterOnActivityPausedListener = method;mUnregisterOnActivityPausedListener.setAccessible(true);}}mUnregisterOnActivityPausedListener.invoke(activityThread,this,fForegroundDispatchListener.get(nfcAdapter));} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}

需要注意的是,以上反射需要systemuid+系统签名的方式,如果不是的话,反射的时候这两个方法是找不到的。

如果是有系统源码的话,那就在这个nfcadapter里面做一些手脚,比如在反注册前读取一下某个标志位决定是否真的反注册。

http://www.xdnf.cn/news/12119.html

相关文章:

  • 知识蒸馏:从模型输出到深层理解
  • 论文笔记——相干体技术在裂缝预测中的应用研究
  • kafka入门学习
  • 蓝桥杯2118 排列字母
  • 10_聚类
  • llm-d:面向Kubernetes的高性能分布式LLM推理框架
  • react私有样式处理
  • Nuxt.js 入门总结教程
  • 汇编语言综合程序设计:子程序、分支与循环深度解析
  • 灾难恢复演练:数据库备份与恢复的全流程实践
  • [测试_10] Selenium IDE | cssSelector | XPath | 操作测试
  • 9.axios底层原理,和promise的对比(2)
  • BLOB 是用来存“二进制大文件”的字段类型
  • 时间获取函数
  • 制作官网水平导航栏
  • 开源供应链攻击持续发酵,多个软件包仓库惊现恶意组件
  • 捍卫低空安全!-中科固源发现无人机MavLink协议远程内存泄漏漏洞
  • 设计模式(代理设计模式)
  • 墨者学院-密码学实训隐写术第二题
  • 【C++快读快写】
  • nt!CcMapData函数分析之Loop to touch each page触发nt!MmAccessFault函数----NTFS源代码分析之四
  • 中国西部逐日1 km全天候地表温度数据集(TRIMS LST-TP;2000-2024)
  • npm run dev 报错:Error: error:0308010C:digital envelope routines::unsupported
  • UDP:简洁高效的报文结构解析与关键注意事项
  • std::conditional_t一个用法
  • [10-2]MPU6050简介 江协科技学习笔记(22个知识点)
  • MVCC机制:Undo Log版本链与ReadView机制
  • Python Excel 文件处理:openpyxl 与 pandas 库完全指南
  • 使用高斯朴素贝叶斯算法对鸢尾花数据集进行分类
  • 数据库优化实战分享:高频场景下的性能调优技巧与案例解析