系统截图和 adb 截图

发布时间:2025-06-24 20:41:34  作者:北方职教升学中心  阅读量:712


系统截图和 adb 截图。截图原理

在这里插入图片描述
我们的手机一般同时按下音量-键和电源键就会将当前屏幕显示的内容截取下来,那里面具体经过哪些流程呢?

Android中每一个页面都是一个Activity,通过Window对象实现页面的显示,每个Window对象实际上都是PhoneWindow的实例,当我们在Activity页面点击屏幕的时候,会触发点击事件,这个事件会一层层分发到处理它的view上,大致会经过这些view:
在这里插入图片描述
先会调PhoneWindowManager中的dispatchUnhandledKey方法,一层层往下,这里不详细展开,我们往下找会发现最终会调用一个takeScreenshot截屏的方法:

privatevoidtakeScreenshot(){synchronized(mScreenshotLock){if(mScreenshotConnection !=null){return;}ComponentNamecn =newComponentName("com.android.systemui","com.android.systemui.screenshot.TakeScreenshotService");Intentintent =newIntent();intent.setComponent(cn);ServiceConnectionconn =newServiceConnection(){@OverridepublicvoidonServiceConnected(ComponentNamename,IBinderservice){synchronized(mScreenshotLock){if(mScreenshotConnection !=this){return;}Messengermessenger =newMessenger(service);Messagemsg =Message.obtain(null,1);finalServiceConnectionmyConn =this;Handlerh =newHandler(mHandler.getLooper()){@OverridepublicvoidhandleMessage(Messagemsg){synchronized(mScreenshotLock){if(mScreenshotConnection ==myConn){mContext.unbindService(mScreenshotConnection);mScreenshotConnection =null;mHandler.removeCallbacks(mScreenshotTimeout);}}}};msg.replyTo =newMessenger(h);msg.arg1 =msg.arg2 =0;if(mStatusBar !=null&&mStatusBar.isVisibleLw())msg.arg1 =1;if(mNavigationBar !=null&&mNavigationBar.isVisibleLw())msg.arg2 =1;try{messenger.send(msg);}catch(RemoteExceptione){}}}@OverridepublicvoidonServiceDisconnected(ComponentNamename){}};if(mContext.bindServiceAsUser(intent,conn,Context.BIND_AUTO_CREATE,UserHandle.CURRENT)){mScreenshotConnection =conn;mHandler.postDelayed(mScreenshotTimeout,10000);}}}

这里通过反射机制调用了TakeScreenshotService的bindServiceAsUser方法,创建TakeScreenshotService服务,再通过其内部的SurfaceControl.screenshot 生成 bitmap,生成图片成功会给系统发送通知。实现方式

Android 截图主要为四种:View 截图、实现方式

    • 1. View截图
    • 2. WebView截图
    • 3. 屏幕截图
  • 三、格式转换方法

    下面列出了一些常用的转换方法:

    // Bitmap 转 Base64privatestaticStringgetBitmapString(Bitmapbitmap){Stringresult =null;ByteArrayOutputStreamout =null;try{if(bitmap !=null){out =newByteArrayOutputStream();bitmap.compress(Bitmap.CompressFormat.PNG,100,out);​      out.flush();out.close();byte[]bitmapBytes =out.toByteArray();result =Base64.encodeToString(bitmapBytes,Base64.DEFAULT);}}catch(IOExceptione){e.printStackTrace();}finally{try{if(out !=null){out.flush();out.close();}}catch(IOExceptione){e.printStackTrace();}}returnresult;}// Bitmap 转 Byteprivatestaticbyte[]getBitmapByte(Bitmapbitmap){ByteArrayOutputStreamout =newByteArrayOutputStream();// 转换类型,压缩质量,字节流资源bitmap.compress(Bitmap.CompressFormat.PNG,100,out);try{out.flush();out.close();}catch(IOExceptione){e.printStackTrace();}returnout.toByteArray();}// Drawable 转 BitmappublicstaticBitmaptoBitmap(Drawabledrawable){if(drawable instanceofBitmapDrawable){return((BitmapDrawable)drawable).getBitmap();}elseif(drawable instanceofColorDrawable){//colorBitmapbitmap =Bitmap.createBitmap(32,32,Bitmap.Config.ARGB_8888);Canvascanvas =newCanvas(bitmap);canvas.drawColor(((ColorDrawable)drawable).getColor());returnbitmap;}elseif(drawable instanceofNinePatchDrawable){//.9.pngBitmapbitmap =Bitmap.createBitmap(drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight(),Bitmap.Config.ARGB_8888);Canvascanvas =newCanvas(bitmap);drawable.setBounds(0,0,drawable.getIntrinsicWidth(),drawable.getIntrinsicHeight());drawable.draw(canvas);returnbitmap;}returnnull;}
  • 截图原理
  • 二、

    二、屏幕截图、

    系统截图的大致流程就是这样,在里面截图原理大致就是:获取需要截屏的区域的宽高,创建一个画布,然后区域内的内容绘制在画布上,最后生成bitmap图片。WebView 截图、

    1. View截图

    可以截取到View不可见的部分,生成长图,状态栏和导航栏无法截到
    在这里插入图片描述

    funscreenshotView(view:ViewGroup):Bitmap?{varh =0varbitmap:Bitmap?=nullfor(i in0until view.childCount){h +=view.getChildAt(i).height        view.getChildAt(i).setBackgroundColor(Color.parseColor("#6CC287"))}bitmap =Bitmap.createBitmap(view.width,h,Bitmap.Config.RGB_565)valcanvas =Canvas(bitmap)view.draw(canvas)//重新赋色for(i in0until view.childCount){view.getChildAt(i).setBackgroundDrawable(null)}returnbitmap}

    2. WebView截图

    WebView 作为一种特殊的控件,不能像其他系统 View 或者截屏的方式来截图,有特定的Api
    在这里插入图片描述

    // 1.capturePicture方法废弃// 2.getScale方法废弃// 3.getDrawingCache方法privatestaticbyte[]screenshotWebView(){Bitmapbitmap =webView.getDrawingCache();byte[]drawByte =getBitmapByte(bmp);returndrawByte;}// 4.draw方法privatestaticbyte[]screenshotWebView(){// webView.setDrawingCacheEnabled(true); 设置缓存Bitmapbitmap =Bitmap.createBitmap(webView.getWidth(),webView.getHeight(),Bitmap.Config.ARGB_8888);Canvascanvas =newCanvas(bitmap);webView.draw(canvas);webView.destroyDrawingCache();byte[]drawByte =getBitmapByte(bitmap);returndrawByte;}

    可能会截取不到 cavans 元素,原因是开启了硬件加速(关闭硬件加速可能导致页面异常),可在 AndroidManifest.xml 中设置:

    android:hardwareAccelerated="false"

    截长图的话需要配置:

    if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.LOLLIPOP){WebView.enableSlowWholeDocumentDraw();}setContentView(R.layout.webview);

    3. 屏幕截图

    截取应用当前屏幕的图片:

    /**     * 获取当前屏幕截图,包含状态栏     *     * @param activity activity     * @return Bitmap     */publicstaticBitmapcaptureWithStatusBar(Activityactivity){Viewview =activity.getWindow().getDecorView();view.setDrawingCacheEnabled(true);view.buildDrawingCache();Bitmapbmp =view.getDrawingCache();intwidth =getScreenWidth(activity);intheight =getScreenHeight(activity);Bitmapret =Bitmap.createBitmap(bmp,0,0,width,height);view.destroyDrawingCache();returnret;}/**     * 获取当前屏幕截图,不包含状态栏     *     * @param activity activity     * @return Bitmap     */publicstaticBitmapcaptureWithoutStatusBar(Activityactivity){Viewview =activity.getWindow().getDecorView();view.setDrawingCacheEnabled(true);view.buildDrawingCache();Bitmapbmp =view.getDrawingCache();intstatusBarHeight =getStatusBarHeight(activity);intwidth =getScreenWidth(activity);intheight =getScreenHeight(activity);Bitmapret =Bitmap.createBitmap(bmp,0,statusBarHeight,width,height -statusBarHeight);view.destroyDrawingCache();returnret;}/**     * 得到屏幕的高     *     * @param context     * @return     */publicstaticintgetScreenHeight(Contextcontext){WindowManagerwm =(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);intheight =wm.getDefaultDisplay().getHeight();returnheight;}/**     * 得到屏幕的宽     *     * @param context     * @return     */publicstaticintgetScreenWidth(Contextcontext){WindowManagerwm =(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);intwidth =wm.getDefaultDisplay().getWidth();returnwidth;}/**     * 获取状态栏高度     *     * @param context 上下文     * @return 状态栏高度     */publicstaticintgetStatusBarHeight(Contextcontext){intresult =0;intresourceId =context.getResources().getIdentifier("status_bar_height","dimen","android");if(resourceId >0){result =context.getResources().getDimensionPixelSize(resourceId);}returnresult;}

    三、

    目录

    • 一、后两种截图不常用,不详细展开。格式转换方法

    一、