简体   繁体   English

使用根视图进行Android屏幕捕获

[英]Android Screen Capture using root view

I am trying to capture the screen 我正在尝试捕获屏幕

    View decorView = activity.getWindow().getDecorView();
    decorView.setDrawingCacheEnabled(true);
    Bitmap bitmap = decorView.getDrawingCache();

Everything is working fine, I am able to take the screenshots. 一切正常,我可以截屏了。 But for one scenario I am facing one issue. 但是对于一种情况,我面临一个问题。 But when there is Dialog fragment, the view of Dialog fragment is not getting captured, but the view of background activity which is partial visible is getting captured as if the root view of activity in the topmost layer. 但是,当存在Dialog片段时,不会捕获Dialog片段的视图,但是会捕获部分可见的背景活动视图,就像在最顶层的活动的根视图一样。

But when there is Dialog fragment, the view of Dialog fragment is not getting captured, but the view of background activity which is partial visible is getting captured as if the root view of activity in the topmost layer. 但是,当存在Dialog片段时,不会捕获Dialog片段的视图,但是会捕获部分可见的背景活动视图,就像在最顶层的活动的根视图一样。

That is because the Dialog is in a separate window. 那是因为Dialog在单独的窗口中。 I am not aware of anything much that you can do about this. 我对此一无所知。

You can get list of decor views for all windows of your app with the help of reflection. 您可以在反射的帮助下获取应用程序所有窗口的装饰视图列表。 This list will contain decor views not only for activities, but also for dialogs and popup windows. 该列表不仅包含活动的装饰视图,还包含对话框和弹出窗口的装饰视图。

void processDialogWindow(Context context) {
    WindowManager windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
    Field globalField = Class.forName("android.view.WindowManagerImpl").getDeclaredField("mGlobal");
    globalField.setAccessible(true);
    Object globalFieldValue = globalField.get(windowManager);
    List<?> viewsFieldValue = getViews(globalFieldValue);
    for (int i = viewsFieldValue.size() - 1; i >= 0; i--) {
        View decorView = (View)viewsFieldValue.get(i);
        WindowManager.LayoutParams castedParams = (WindowManager.LayoutParams)decorView.getLayoutParams();
        if (castedParams.type == WindowManager.LayoutParams.TYPE_APPLICATION) { // Dialog
            //TODO: get decorView screenshot.
        }
    }
}

List<?> getViews(Object globalWindowManager) throws NoSuchFieldException, IllegalAccessException {
    Field viewsField = globalWindowManager.getClass().getDeclaredField("mViews");
    viewsField.setAccessible(true);
    Object viewsFieldValue = viewsField.get(globalWindowManager);
    if (viewsFieldValue instanceof List<?>)
        return (List<?>)viewsFieldValue;
    else if (viewsFieldValue instanceof View[]) {
        return new ArrayList<>(Arrays.asList((View[])viewsFieldValue));
    }
    return null;
}

I have tested this approach on Android 5, 6 and 7. Certainly, when you use reflection, you should check if the value of some field is not null and really has expected type. 我已经在Android 5、6和7上测试了这种方法。当然,当您使用反射时,应该检查某个字段的值是否不为null且确实具有预期的类型。 Thus internal data structures, which are accessed via reflection, can be changed in future versions of Android or by device vendor even in existing Android versions. 因此,可以在将来的Android版本中或通过设备供应商甚至在现有的Android版本中更改通过反射访问的内部数据结构。 I didn't add checks for null or wrong type here for the sake of conciseness. 为了简洁起见,我没有在此处添加对null或错误类型的检查。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM