Android Toast信息定位分析介绍

embedded/2024/11/25 22:56:59/

Android Toast信息定位分析介绍

文章目录

  • Android Toast信息定位分析介绍
    • 一、前言
    • 二、Toast定位
      • 1、系统源码加日志定位Toast信息
        • (1)Toast 的源码位置:
        • (2)添加打印日志:
      • 2、监听无障碍模式下的Toast信息
        • (1)MyAccessibilityService继承自无障碍服务
        • (2)apk中的AndroidManafest.xml声明
        • (3)在res/xml文件夹下新建accessible_service_config_test.xml
    • 三、其他
      • 1、Toast分析小结
      • 2、查看当前界面的信息情况 dumpsys window
      • 2、Android 开发工具箱 apk

一、前言

Android Toast有时候莫名其妙的弹框,需要定位到是哪个应用发出,咋搞?

系统开发的就没啥难度,可以直接在系统源码里面加个打印重新编包验证就行了,
因为Toast需要传入上下文,所以通过上下文是可以获取到应用包名的,和Toast文本信息;

但是如果不是系统源码开发难道就不行了吗,其实也是可以的,
之前安装过一个“Android开发工具箱”的apk应用,开启无障碍模式下就可以监听Toast的信息,包括Toast的包名和文本。

本文介绍一下,上面两种方式定位Toast 的代码实现。

本文不难,有兴趣的可以看看。

二、Toast定位

1、系统源码加日志定位Toast信息

Toast 的简单代码:

Toast.makeText(Context, "Toast Message", Toast.LENGTH_SHORT).show();
(1)Toast 的源码位置:
framework\base\core\java\android\widget\Toast.java
(2)添加打印日志:
public class Toast {static final String TAG = "Toast";...public void show() {INotificationManager service = getService();String pkg = mContext.getOpPackageName();TN tn = mTN;tn.mNextView = new WeakReference<>(mNextView);final boolean isUiContext = mContext.isUiContext();final int displayId = mContext.getDisplayId();//下面的代码就打印了:Toast应用的包名和具体弹框的信息Log.i(TAG, "mybebug show() pkg = " + pkg + ",mText = " + mText);...}
}

就是这么简单加一行信息就行。

如果想要知道这个Toast是哪个应用哪行代码执行的,加入栈堆信息就行:

import android.os.SystemProperties;boolean isNeedLogToast = SystemProperties.getBoolean("persist.sys.debug.need_log_toast", true);if (isNeedLogToast) {Log.i(TAG, "mybebug show() pkg = " + pkg + "mText = " + mText);Exception e = new Exception("LogToast");e.printStackTrace();}

上面加入了prop属性控制,防止一直打印堆栈信息,一般有几十行堆栈信息。
部分日志,如下:


11-07 09:18:20.141  7078  7078 I Toast   : mybebug show() pkg = com.debug.factory,menumText = WiFi is not connected. Please connect and try again130|console:/ # logcat |grep -i System.err                                     
...
11-07 04:35:25.730  2194  2194 W System.err: java.lang.Exception: LogToast
11-07 04:35:25.730  2194  2194 W System.err:    at android.widget.Toast.show(Toast.java:214)
11-07 04:35:25.730  2194  2194 W System.err:    at com.skg.settings.utils.ToastUtils.showToast(ToastUtils.java:36)
11-07 04:35:25.730  2194  2194 W System.err:    at com.skg.settings.utils.ToastUtils.showToast(ToastUtils.java:40)
11-07 04:35:25.730  2194  2194 W System.err:    at com.skg.settings.adapter.WirelessNetworkAdapter$16.run(WirelessNetworkAdapter.java:793)
11-07 04:35:25.731  2194  2194 W System.err:    at android.os.Handler.handleCallback(Handler.java:942)
11-07 04:35:25.731  2194  2194 W System.err:    at android.os.Handler.dispatchMessage(Handler.java:99)
11-07 04:35:25.731  2194  2194 W System.err:    at android.os.Looper.loopOnce(Looper.java:201)
11-07 04:35:25.731  2194  2194 W System.err:    at android.os.Looper.loop(Looper.java:288)
11-07 04:35:25.731  2194  2194 W System.err:    at android.app.ActivityThread.main(ActivityThread.java:7924)
11-07 04:35:25.731  2194  2194 W System.err:    at java.lang.reflect.Method.invoke(Native Method)
11-07 04:35:25.731  2194  2194 W System.err:    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
11-07 04:35:25.731  2194  2194 W System.err:    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)
11-07 04:35:25.758   937  1777 W FileUtils: android.system.ErrnoException: chmod failed: ENOENT (No such file or directory)

上面就可以看到是哪个应用包名下的哪个类的哪行方法执行的Toast,还是比较详细的。

如果不想编译系统源码监听Toast信息,那么就可以使用下面这种方法了。

2、监听无障碍模式下的Toast信息

写一个apk demo吧,挺简单的,主要是一个服务的监听。具体代码如下:

(1)MyAccessibilityService继承自无障碍服务
package com.liwenzhi.audiodemo;import android.accessibilityservice.AccessibilityService;
import android.view.accessibility.AccessibilityEvent;public class MyAccessibilityService extends AccessibilityService {@Overridepublic void onCreate() {super.onCreate();LogUtil.debug("");}@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {LogUtil.debug("event = " + event);// 检查事件类型是否是Toast显示的事件// 检查事件是否来自Toastif (event.getEventType() == AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED) {CharSequence packageName = event.getPackageName();// 获取Toast的文本内容CharSequence toastText = event.getText().toString();if (toastText != null) {// 处理Toast信息,这里打印一下String toastString = toastText.toString();LogUtil.debug("packageName = " + packageName + ", toastString = " + toastString);}}}@Overridepublic void onInterrupt() {// 处理中断事件LogUtil.debug("");}
}

上面的Toast 信息是可以得到打印的,网上有些写法是不太对。
AccessibilityService 也是一个四大组件的Service,所以必须声明。

(2)apk中的AndroidManafest.xml声明
        <serviceandroid:name=".MyAccessibilityService"android:exported="false"android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"><intent-filter><actionandroid:name="android.accessibilityservice.AccessibilityService" /></intent-filter><meta-dataandroid:name="android.accessibilityservice"android:resource="@xml/accessibility_service_config" /></service>

必须要写上面的permission和 meta-data 信息,否则不会给你显示你可以获取到什么权限。
按照上面的写就行了。

(3)在res/xml文件夹下新建accessible_service_config_test.xml

内容如下:

<?xml version="1.0" encoding="utf-8"?>
<!-- typeAllMask:接收所有事件。
==========窗口事件相关(常用)==========
typeWindowStateChanged:监听窗口状态变化,比如打开一个popupWindow,dialog,Activity切换等等。
typeWindowContentChanged:监听窗口内容改变,比如根布局子view的变化。
typeWindowsChanged:监听屏幕上显示的系统窗口中的事件更改。 此事件类型只应由系统分派。
typeNotificationStateChanged:监听通知变化,比如notifacation和toast。
============View事件相关==========
typeViewClicked:监听view点击事件。
typeViewLongClicked:监听view长按事件。
typeViewFocused:监听view焦点事件。
typeViewSelected:监听AdapterView中的上下文选择事件。
typeViewTextChanged:监听EditText的文本改变事件。
typeViewHoverEnter、typeViewHoverExit:监听view的视图悬停进入和退出事件。
typeViewScrolled:监听view滚动,此类事件通常不直接发送。
typeViewTextSelectionChanged:监听EditText选择改变事件。
typeViewAccessibilityFocused:监听view获得可访问性焦点事件。
typeViewAccessibilityFocusCleared:监听view清除可访问性焦点事件。
============手势事件相关==========
typeGestureDetectionStart、typeGestureDetectionEnd:监听手势开始和结束事件。
typeTouchInteractionStart、typeTouchInteractionEnd:监听用户触摸屏幕事件的开始和结束。
typeTouchExplorationGestureStart、typeTouchExplorationGestureEnd:监听触摸探索手势的开始和结束。
android:description :辅助功能描述,描述该辅助功能用来干嘛的
android:packageNames :指定辅助功能监听的包名,不指定表示监听所有应用
android:accessibilityEventTypes:辅助功能处理事件类型,一般配置为typeAllMask表示接收所有事件
android:accessibilityFlags:辅助功能查找截点方式,一般配置为flagDefault默认方式。
android:accessibilityFeedbackType:操作相应按钮以后辅助功能给用户的反馈类型,包括声音,震动等。
android:notificationTimeout:相应时间设置
android:canRetrieveWindowContent:是否允许辅助功能获得窗口的节点信息,为了能正常实用辅助功能,请务必保持该项配置为true 
--><accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"android:description="@string/app_name"android:accessibilityEventTypes="typeAllMask"android:accessibilityFeedbackType="feedbackGeneric"android:notificationTimeout="100"android:canRetrieveWindowContent="true"android:accessibilityFlags="flagDefault" />

如果要监听整个系统的Toast信息,就不要写packageNames 标签信息,否则会只监听某个应用的Toast信息;

另外 description 标签信息必须要写成@string 形式,直接写字符串是编译不通过的,随便链接一个@string的字符串都是可以的。

上面是监听所有事件,界面发生改变或者点击到设备屏幕,都会收到相关事件信息。

网上有的说要申请权限BIND_ACCESSIBILITY_SERVICE:

<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />

其实不用也可以,Service 那里声明就可以了。

三、其他

1、Toast分析小结

两种方式可以定位到Toast是哪里发出的;
一种是在系统源码Toast.java里面加打印;
另外一种是监听"无障碍服务"AccessibilityService的动作,获取Toast 的信息。

2、查看当前界面的信息情况 dumpsys window

dumpsys window信息非常多,一般都是grep过滤查看当前焦点的界面信息。

console:/ # //Launcher界面时
console:/ # dumpsys window | grep mFocmFocusedApp=ActivityRecord{329e2a3 u0 com.android.launcher3/.uioverrides.QuickstepLauncher t31}mFocusedWindow=Window{94e847d u0 com.android.launcher3/com.android.launcher3.uioverrides.QuickstepLauncher}
console:/ # 
console:/ # //打开原生设置界面时
console:/ # dumpsys window | grep mFoc                                         mFocusedApp=ActivityRecord{7337aee u0 com.android.settings/.SubSettings t34}mFocusedWindow=Window{d562574 u0 com.android.settings/com.android.settings.SubSettings}
console:/ #  //打开谷歌文件管理器界面时
console:/ # dumpsys window | grep mFoc                                         mFocusedApp=ActivityRecord{51e0ddd u0 com.google.android.apps.nbu.files/.documentbrowser.filepreview.FilePreviewActivity t33}mFocusedWindow=Window{fe3284d u0 com.google.android.apps.nbu.files/com.google.android.apps.nbu.files.documentbrowser.filepreview.FilePreviewActivity}
console:/ # 

上面可以获取到当前应用的哪个Activity界面,但是还无法获取到Fragment界面,
如果要获取到Fragment或者具体控件的信息,也是可以使用无障碍服务获取到的,有需要的自行研究看看。

2、Android 开发工具箱 apk

Android 开发工具箱 apk
2024年11 月下载的,是2024下半年的apk,从网页上也是可以搜索发现: “Android开发工具箱” apk应用
里面主要功能:
系统基本信息显示(分辨率、wifi连接情况),屏幕测距,二维码识别,跳转到系统设置界面、开发者选项界面等,权限统计,
应用信息查看,通知和消息监听,Activity界面监听等功能是免费查看的。
apk反编译、签名需要收费。

https://download.csdn.net/download/wenzhi20102321/89975054


http://www.ppmy.cn/embedded/140496.html

相关文章

MySQL中的ROW_NUMBER窗口函数简单了解下

ROW_NUMBER() 是 MySQL8引入的窗口函数之一&#xff0c;它为查询结果集中的每一行分配一个唯一的顺序号&#xff08;行号&#xff09;。这个顺序号是基于窗口函数的 ORDER BY 子句进行排序的&#xff0c;可以根据指定的排序顺序生成连续的整数值。 ROW_NUMBER() 在分页、去重、…

R语言4.3.0安装教程【附安装包】

R for Windows是一个免费的用于统计计算和统计制图的优秀工具&#xff0c;是R语言开发工具。它拥有数据存储和处理系统、数组运算工具&#xff08;其向量、矩阵运算方面功能尤其强大&#xff09;、完整连贯的统计分析工具、优秀的统计制图等功能。提供的图形界面&#xff0c;可…

大数据实验4-HBase

一、实验目的 阐述HBase在Hadoop体系结构中的角色&#xff1b;能够掌握HBase的安装和配置方法熟练使用HBase操作常用的Shell命令&#xff1b; 二、实验要求 学习HBase的安装步骤&#xff0c;并掌握HBase的基本操作命令的使用&#xff1b; 三、实验平台 操作系统&#xff1…

神经网络(系统性学习四):深度学习——卷积神经网络(CNN)

相关文章&#xff1a; 神经网络中常用的激活函数神经网络&#xff08;系统性学习一&#xff09;&#xff1a;入门篇神经网络&#xff08;系统性学习二&#xff09;&#xff1a;单层神经网络&#xff08;感知机&#xff09;神经网络&#xff08;系统性学习三&#xff09;&#…

CentOS操作系统下安装Nacos

CentOS下安装Nacos 前言 这在Centos下安装配置Nacos 下载Linux版Nacos 首先到Nacos的 Github页面&#xff0c;找到所需要安装的版本 也可以右键复制到链接&#xff0c;然后通过wget命令进行下载 wget https://github.com/alibaba/nacos/releases/download/1.3.2/nacos-ser…

【MySQL数据库】C#实现MySQL数据库最简单的查询和执行函数

文章目录 前言一、查询方法二、执行方法 前言 C#和MySQL数据库是常见的数据交互&#xff0c;标准的查询和执行方法如下&#xff0c;做个记录。 一、查询方法 private static int QueryTable(string tableName, DateTime today, string stepName){int result 0; // 返回数据…

基于python的机器学习(四)—— 聚类(一)

目录 一、聚类的原理与实现 1.1 聚类的概念和类型 1.2 如何度量距离 1.2.1 数据的类型 1.2.2 连续型数据的距离度量方法 1.2.3 离散型数据的距离度量方法 1.3 聚类的基本步骤 二、层次聚类算法 2.1 算法原理和实例 2.2 算法的Sklearn实现 2.2.1 层次聚类法的可视化实…

C++自动化测试:GTest 与 GitLab CI/CD 的完美融合

在现代软件开发中&#xff0c;自动化测试是保证代码质量和稳定性的关键手段。对于C项目而言&#xff0c;自动化测试尤为重要&#xff0c;它能有效捕捉代码中的潜在缺陷&#xff0c;提高代码的可维护性和可靠性。本文将重点介绍如何在C项目中结合使用Google Test&#xff08;GTe…