Skip to content

Android 免Root截屏

ythy edited this page Nov 17, 2017 · 1 revision
  1. 用户访问许可, 需要在Activity进行
MediaProjectionManager mProjectionManager = (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
startActivityForResult(mProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
  1. 通过 onActivityResult() 回调, 启动截屏service
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_CODE) {
            ScreenshotService.setResultData(data);
            Intent intent = new Intent(getApplicationContext(), ScreenshotService.class);
            intent.putExtra("position_x", getIntent().getIntExtra("position_x", 0));
            intent.putExtra("position_y", getIntent().getIntExtra("position_y", 0));
            startService(intent);
            this.finish();
        }
    }
  1. service中取得手机测量信息
        mMetrics = new DisplayMetrics();
        WindowManager mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        mWindowManager.getDefaultDisplay().getMetrics(mMetrics);
        mScreenDensity = mMetrics.densityDpi;
        mScreenWidth = mMetrics.widthPixels;
        mScreenHeight = mMetrics.heightPixels;
  1. 创建ImageReader 获取处理图片
        mImageReader = ImageReader.newInstance(mScreenWidth, mScreenHeight, PixelFormat.RGBA_8888, 1);
        mImageReader.setOnImageAvailableListener(onImageAvailableListener, null);
  1. 设置MediaProjection 启动截屏
    private MediaProjectionManager getMediaProjectionManager() {
        return (MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
    }
    mMediaProjection = getMediaProjectionManager().getMediaProjection(Activity.RESULT_OK, mResultData);
  1. 创建VirtualDisplay 捕获截屏
      mVirtualDisplay = mMediaProjection.createVirtualDisplay(SCREENCAP_NAME,
                mScreenWidth, mScreenHeight, mScreenDensity,
                VIRTUAL_DISPLAY_FLAGS,
                mImageReader.getSurface(), null, null);
  1. OnImageAvailableListener 监听函数中处理图片
        @Override
        public void onImageAvailable(ImageReader reader) {
            Log.i(TAG, "in OnImageAvailable");
            Image image = null;
            FileOutputStream fos = null;
            Bitmap bitmap = null;
            try {
                image = reader.acquireLatestImage();
                if (image != null) {
                    Image.Plane[] planes = image.getPlanes();
                    if (planes[0].getBuffer() == null) {
                        return;
                    }
                    int width = image.getWidth();
                    int height = image.getHeight();
                    int pixelStride = planes[0].getPixelStride();
                    int rowStride = planes[0].getRowStride();
                    int rowPadding = rowStride - pixelStride * width;

                    int offset = 0;
                    bitmap = Bitmap.createBitmap(mMetrics, width, height, Bitmap.Config.ARGB_8888);
                    ByteBuffer buffer = planes[0].getBuffer();
                    for (int i = 0; i < height; ++i) {
                        for (int j = 0; j < width; ++j) {
                            int pixel = 0;
                            pixel |= (buffer.get(offset) & 0xff) << 16;     // R
                            pixel |= (buffer.get(offset + 1) & 0xff) << 8;  // G
                            pixel |= (buffer.get(offset + 2) & 0xff);       // B
                            pixel |= (buffer.get(offset + 3) & 0xff) << 24; // A
                            bitmap.setPixel(j, i, pixel);
                            offset += pixelStride;
                        }
                        offset += rowPadding;
                    }
                    // write bitmap to a file
                    String fileName = FileUtil.getScreenShotsName(getApplicationContext());
                    fos = new FileOutputStream(fileName);
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
                    Toast.makeText(getApplicationContext(), "screenshot captured", Toast.LENGTH_SHORT).show();
                    CommonUtils.refreshMediaScanner(getApplicationContext(), new File(fileName));
                    onBack();
                }

            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }
                }
                if (bitmap != null) {
                    bitmap.recycle();
                }
                if (image != null) {
                    image.close();
                }
                stopImageReader();
            }
         }

  1. 关闭各对象
   private void stopMediaProjection() {
        if (mMediaProjection != null) {
            mMediaProjection.stop();
            mMediaProjection = null;
        }
    }

    private void stopVirtual() {
        if (mVirtualDisplay != null) {
            mVirtualDisplay.release();
            mVirtualDisplay = null;
        }
    }

    private void stopImageReader(){
        if(mImageReader != null){
            mImageReader.setOnImageAvailableListener(null, null);
            mImageReader.close();
        }
    }

遇到的问题

  1. 模拟器不能正常截屏,图片是空白
  2. 实测截屏,边部显示异常,需要上述RGBA->ARGB处理, 此处理耗时,待优化
  3. onActivityResult 回调有可能不能触发, 参考之前wiki中的处理方案
  4. onImageAvailable 会执行多次,单张截屏需要及时把imageReader close掉
Clone this wiki locally