Android 是否有一种方法可以通过编程方式定位给定应用程序中的所有窗口?
是否可以通过编程方式枚举应用程序中的所有Android 是否有一种方法可以通过编程方式定位给定应用程序中的所有窗口?,android,android-view,android-window,Android,Android View,Android Window,是否可以通过编程方式枚举应用程序中的所有android.view.Windows或装饰视图 例如,对话框将在新的窗口中打开,与主活动窗口分开。我可以通过Dialog.getWindow()找到它们,但我不确定如何使用内置组件(如“活动”菜单弹出窗口)实现这一点 是否有任何方法可以从应用程序、上下文、或窗口管理器、或其他方式枚举与我的应用程序关联的窗口 我可以使用adb dumpsys window查看我的应用程序的所有窗口,但我正在寻找一种在我的应用程序中执行此操作而不需要root的方法。我找到
android.view.Window
s或装饰视图
例如,对话框
将在新的窗口
中打开,与主活动窗口分开。我可以通过Dialog.getWindow()
找到它们,但我不确定如何使用内置组件(如“活动”菜单弹出窗口)实现这一点
是否有任何方法可以从应用程序
、上下文
、或窗口管理器
、或其他方式枚举与我的应用程序关联的窗口
我可以使用adb dumpsys window查看我的应用程序的所有窗口,但我正在寻找一种在我的应用程序中执行此操作而不需要root的方法。我找到了一种方法,通过在
@hidden windowmanager global
上的反射来执行此操作。至少到目前为止,我知道这适用于android-18
private void logRootViews() {
try {
Class wmgClass = Class.forName("android.view.WindowManagerGlobal");
Object wmgInstnace = wmgClass.getMethod("getInstance").invoke(null, (Object[])null);
Method getViewRootNames = wmgClass.getMethod("getViewRootNames");
Method getRootView = wmgClass.getMethod("getRootView", String.class);
String[] rootViewNames = (String[])getViewRootNames.invoke(wmgInstnace, (Object[])null);
for(String viewName : rootViewNames) {
View rootView = (View)getRootView.invoke(wmgInstnace, viewName);
Log.i(TAG, "Found root view: " + viewName + ": " + rootView);
}
} catch (Exception e) {
e.printStackTrace();
}
}
输出:
找到根视图:
com.example.paintsample/com.example.paintsample.paintsample/android.view。ViewRootImpl@41deeff0:
com.android.internal.policy.impl.PhoneWindow$DecorView{41dcc278
V.E…..R…..0,0-7681184}
找到根视图:
PopupWindow:42887380/android.view。ViewRootImpl@42891820:
android.widget.PopupWindow$PopupViewContainer{42891450 V.E。。。。。
……0,0-424618}
当然,对于任何能找到更好方法的人来说,悬赏仍然是值得一试的:)SDK附带的工具是值得一试的。我不完全确定这是否回答了实际问题,但这是一种更好的方法,可以获得公认答案中建议的所有根视图 如前所述,我还成功地仅使用反射实现了这一点,但此代码支持API 14及以上版本的所有版本(我在下面没有检查):
公共静态列表getWindowManagerView(){
试一试{
如果(Build.VERSION.SDK\u INT>=Build.VERSION\u code.ICE\u CREAM\u三明治&&
Build.VERSION.SDK\u INT=Build.VERSION\u code.JELLY\u BEAN\u MR1){
//从WindowManagerGlobal.mViews获取列表
类wmgClass=Class.forName(“android.view.WindowManagerGlobal”);
对象wmgInstance=wmgClass.getMethod(“getInstance”).invoke(null);
返回视图fromWM(wmgClass,wmgInstance);
}
}捕获(例外e){
e、 printStackTrace();
}
返回新的ArrayList();
}
私有静态列表视图FromWM(类wmClass,对象wmInstance)引发异常{
Field viewsField=wmClass.getDeclaredField(“mViews”);
viewsField.setAccessible(true);
对象视图=viewsField.get(wmInstance);
如果(视图实例列表){
返回(列表)viewsField.get(wmInstance);
}else if(视图实例视图[]){
返回Arrays.asList((View[])viewsField.get(wmInstance));
}
返回新的ArrayList();
}
通过访问类文件,然后将其添加到android SDK中的android.jar,您可以直接使用@hidden API,而无需使用反射。以下是方法:
具体android版本(19,21,22,23,24)的android.jar的源代码可以在这里获取:
因此,您可以直接使用WindowManagerGlobal类来获取所有根视图,如
private void logRootViews() {
WindowManagerGlobal windowManagerGlobal = WindowManagerGlobal.getInstance();
String[] rootViewNames = windowManagerGlobal.getViewRootNames();
for (String viewName : rootViewNames) {
View rootView = windowManagerGlobal.getRootView(viewName);
Log.i("", "Root view is: " + viewName + ": " + rootView);
/*do what you want with the rootView*/
}
}
输出:
根视图是:com.example.paintsample/com.example.paintsample.paintsample/android.view。ViewRootImpl@41deeff0:com.android.internal.policy.impl.PhoneWindow$DecorView{41dcc278 V.E...R...0,0-7681184}
根视图是:PopupWindow:42887380/android.view。ViewRootImpl@42891820:android.widget.PopupWindow$PopupViewContainer{42891450 V.E…...0,0-424618}每个解决方案都在上面的Java中,我为Kotlin转换用户的答案制定了解决方案-
try
{
val wmgClass = Class.forName("android.view.WindowManagerGlobal")
val wagInstance = wmgClass.getMethod("getInstance").invoke(null)
val getViewRootNames: Method = wmgClass.getMethod("getViewRootNames")
val getRootView: Method = wmgClass.getMethod("getRootView", String::class.java)
val rootViewNames = getViewRootNames.invoke(wagInstance) as Array<String>
for (viewName in rootViewNames) {
val rootView = getRootView.invoke(wagInstance, viewName) as View
}
} catch (exception: java.lang.Exception {}
试试看
{
val wmgClass=Class.forName(“android.view.WindowManagerGlobal”)
val wagInstance=wmgClass.getMethod(“getInstance”).invoke(null)
val getViewRootNames:Method=wmgClass.getMethod(“getViewRootNames”)
val getRootView:Method=wmgClass.getMethod(“getRootView”,String::class.java)
val rootViewNames=getViewRootNames.invoke(wagInstance)作为数组
for(rootViewName中的viewName){
val rootView=getRootView.invoke(wagInstance,viewName)作为视图
}
}catch(异常:java.lang.exception{}
那些有能力使用minSdk 29
的人可以使用。在内部,它指的是WindowManagerGlobal
中的mViews
属性,但可供公众使用。活动菜单弹出窗口的窗口与活动的窗口相同,即activity.getWindow()不适合你?不幸的是,不适合。我正在运行android FingerPaint示例(在4.3上),在我点击三点菜单按钮后,我可以在监视器中看到弹出窗口在它自己的窗口中。我还可以运行“adb shell dumpsys window tokens”,并看到paint应用程序确实有两个与其相关联的窗口:allAppWindows=[window]{418f9ce8 u0 com.example.paintsample/com.example.paintsample.paintsample},窗口{41a06d08 u0 PopupWindow:41ac65a0}]对话框也一样。只是好奇,你为什么需要这些信息,或者说,一旦你有了这些信息,你打算怎么处理它?@Josh我正在编写一个库,用于在给定的应用程序中拍摄屏幕截图。只需在根视图上调用getDrawingCache就足够简单了,但为了包含像重叠对话框这样的东西,它们不是同一个窗口hiera阿奇,我不得不跳过这道障碍。哇,祝你好运,听起来很痛苦:)是我吗
try
{
val wmgClass = Class.forName("android.view.WindowManagerGlobal")
val wagInstance = wmgClass.getMethod("getInstance").invoke(null)
val getViewRootNames: Method = wmgClass.getMethod("getViewRootNames")
val getRootView: Method = wmgClass.getMethod("getRootView", String::class.java)
val rootViewNames = getViewRootNames.invoke(wagInstance) as Array<String>
for (viewName in rootViewNames) {
val rootView = getRootView.invoke(wagInstance, viewName) as View
}
} catch (exception: java.lang.Exception {}