android屏幕截屏

Android5.0之前如果希望截图屏幕需要系统权限root,在5.0之后开发了接口android.media.projection,使用该接口,第三方程序无需root权限也可以直接进行屏幕截图操作了。

由于使用了媒体的映射技术手段,故截取的屏幕并不是真正的设备屏幕,而是截取的通过映射出来的“虚拟屏幕”。不过,因为截图我们希望得到的只是一张图片而已,而“映射”出来的图片与系统屏幕完全一致,所以,对于普通屏幕截屏操作,该方法是可行的。

MediaProjection使用步骤:
首先获取MediaProjectionManager,和其他的Manager一样通过 Context.getSystemService() 传入参数MEDIA_PROJECTION_SERVICE获得
接着调用MediaProjectionManager.createScreenCaptureIntent(),调用后会弹出一个dialog询问用户是否授权应用捕捉屏幕
然后在onActivityResult()中获取授权结果

如果授权成功,通过MediaProjectionManager.getMediaProjection(int resultCode, Intent resultData)获取MediaProjection实例,通过MediaProjection.createVirtualDisplay(String name, int width, int height, int dpi, int flags, Surface surface, VirtualDisplay.Callback callback, Handler handler)创建VirtualDisplay实例。实际上在上述方法中传入的surface参数是真正用来截屏或者录屏的。

方法代码

 private static MediaProjectionManager mediaProjectionManager;
    private static MediaProjection mediaProjection;
    private static ImageReader imageReader;

    private static VirtualDisplay mVirtualDisplay = null;

    public static void startScreenCap(Activity context,int screenWidth,int screenHeight) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
            return;
        }
        if (mediaProjectionManager == null)
            mediaProjectionManager = (MediaProjectionManager) context.getSystemService(Context.MEDIA_PROJECTION_SERVICE);

        if(imageReader==null)
            imageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 1);

        context.startActivityForResult(mediaProjectionManager.createScreenCaptureIntent(), ConstantUtils.SCREEN_CAPTURE);
    }


    //获取MediaProjection实例
    public static void setUpMediaProjection(Activity context, Intent data, int screenWidth, int screenHeight,int screenDensity) {
        if(mediaProjection == null)
            mediaProjection = mediaProjectionManager.getMediaProjection(Activity.RESULT_OK, data);
    }

    //获取当前屏幕的内容,mImageReader.getSurface()被传入,屏幕的数据也将会在ImageReader中的Surface中
    public static void virtualDisplay(int screenWidth, int screenHeight, int mScreenDensity) {
        try {
            mVirtualDisplay = mediaProjection.createVirtualDisplay("screen-mirror", screenWidth, screenHeight, mScreenDensity,
                    DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
                    imageReader.getSurface(), null, null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //生成图像
    public static Bitmap createPicture(int screenWidth,int screenHeight) {
        final Image image = imageReader.acquireLatestImage();
        int width = image.getWidth();
        int height = image.getHeight();
        final Image.Plane[] planes = image.getPlanes();
        final ByteBuffer buffer = planes[0].getBuffer();
        int pixelStride = planes[0].getPixelStride();
        int rowStride = planes[0].getRowStride();
        int rowPadding = rowStride - pixelStride * width;
        Bitmap bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
        bitmap.copyPixelsFromBuffer(buffer);
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height);
        image.close();
        return bitmap;

    }

    public static void stopVirtual() {
        if (mVirtualDisplay == null) {
            return;
        }
        mVirtualDisplay.release();
        mVirtualDisplay = null;
    }


通过调用方法

startScreenCap(activity,ScreenUtils.getScreenWidth(activity),ScreenUtils.getScreenHeight(activity));初始化并授权
 
 

在Activity的onResult()方法中调用

public static void capOnActivityResult(final Activity context, int requestCode, int resultCode, final Intent data, final int screenWidth, final int screenHeight, final int screenDensity){
    if(requestCode == ConstantUtils.SCREEN_CAPTURE  && resultCode==Activity.RESULT_OK && data != null){
        singleExecutor.execute(new Runnable() {
            @Override
            public void run() {
                ScreenCaptureUtils.setUpMediaProjection(context,data,screenWidth,screenHeight,screenDensity);
                ScreenCaptureUtils.virtualDisplay(screenWidth,screenHeight,screenDensity);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                BitmapUtils.saveImageToGallery(context, ScreenCaptureUtils.createPicture(screenWidth,screenHeight));
                ScreenCaptureUtils.stopVirtual();
            }
        });
    }
}

 
 



扫描二维码关注公众号,回复: 2282193 查看本文章


原文地址:

关于Android5.0以上屏幕截图探索总结:

https://blog.csdn.net/gulinxieying/article/details/50164469


Android截屏的几种方式:

https://www.2cto.com/kf/201602/488933.html


5.0之前屏幕截屏:

https://www.cnblogs.com/baiqiantao/p/5b9d046a774000e292d1ab22a07a20b1.html


Android5.0屏幕截屏与录制:

https://blog.csdn.net/zhang_jun_ling/article/details/52558243


Android5.0之前屏幕截图的方法:

https://www.cnblogs.com/baiqiantao/p/5b9d046a774000e292d1ab22a07a20b1.html


Android5.0及以上实现屏幕截屏:

https://www.jianshu.com/p/6c2e896b71e0


2、遇到的问题:

  Process: com.example.applications, PID: 12529

                                                                          java.lang.NullPointerException: Attempt to invoke virtual method 'int android.media.Image.getWidth()' on a null object reference

可能的原因及解决办法:

mediaProjection.createVirtualDisplay与imageReader.acquireLatestImage();之间需要间隔最少1s的时间

②根据源码可知resultCode必须为Activity.RESULT_OK ,intentData不能为null

    public MediaProjection getMediaProjection(int resultCode, @NonNull Intent resultData) {
        if (resultCode != Activity.RESULT_OK || resultData == null) {
            return null;
        }
        IBinder projection = resultData.getIBinderExtra(EXTRA_MEDIA_PROJECTION);
        if (projection == null) {
            return null;
        }
        return new MediaProjection(mContext, IMediaProjection.Stub.asInterface(projection));
    }

imageReader = ImageReader.newInstance(screenWidth, screenHeight, PixelFormat.RGBA_8888, 1);
imagereader必须在方法createVirtualDisplay方法之前调用

mediaProjection.createVirtualDisplay("screen-mirror", screenWidth, screenHeight, mScreenDensity,
        DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
        imageReader.getSurface(), null, null);
④所需要的参数screenWidth、screenHeight、screenDensity的值不正确


                                                                          


猜你喜欢

转载自blog.csdn.net/nicolelili1/article/details/80307440