「Android」后盾截屏的初步实现
须要明确,在 Android 中,如果只是想得到正在运行的应用程序本身的界面,是非常简单的,只须要基于 View 对象即可实现截屏个性,具体此处不再赘述。但如果是想从后盾服务中实时的截屏,获取除了应用程序本身以外的其余界面,则须要依赖于 MediaProjectionManager 类。
以下为后盾截屏的简略步骤和对应代码:
- 新建通明 Activity
- 启动截屏 Service
新建通明 Activity
首先,新建一个通明 Activity(新建通明 Activity 的次要起因是,startActivityForResult() 办法为 Activity 类的对象办法,必须得有一个 Activity 作为“母体”),并在在这个 Activity 中调用 requestCaptureScreen() 办法,在该办法中初始化了若干截屏相干数值并通过 createScreenCaptureIntent()) 办法向用户发动截屏申请:
private void requestCaptureScreen() {Log.d(TAG, "requestCaptureScreen:");
Display display = this.getWindowManager().getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
mWidth = metrics.widthPixels;
mHeight = metrics.heightPixels;
mDpi = metrics.densityDpi;
mMediaProjectionManager = (MediaProjectionManager) this.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
if (mMediaProjectionManager != null) {
// 要害代码
this.startActivityForResult(mMediaProjectionManager.createScreenCaptureIntent(), REQUEST_CODE);
}
}
在调用 startActivityForResult() 办法后,须要重写 onActivityResult() 办法,在该办法中当确认获取到用户受权后,启动截屏 Service:
@SuppressLint("WrongConstant")
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {Log.d(TAG, "onActivityResult: InvisibleActivity");
if (requestCode == REQUEST_CODE && resultCode == RESULT_OK) {Intent service = new Intent(this, ScreenShotService.class);
service.putExtra("resultCode", resultCode);
service.putExtra("data", data);
service.putExtra("mWidth", mWidth);
service.putExtra("mHeight", mHeight);
service.putExtra("mDpi", mDpi);
startForegroundService(service);
}
}
启动截屏 Service
在截屏 Service 启动后,别离获取到 MediaProjectionManager 对象和 MediaProjection 对象,并调用 captureScreen() 办法开始截屏并获取截屏文件的门路:
@Override
public int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "onStartCommand: ScreenShotService");
createNotificationChannel();
int resultCode = intent.getIntExtra("resultCode", 0);
Intent data = intent.getParcelableExtra("data");
int width = intent.getIntExtra("mWidth", 0);
int height = intent.getIntExtra("mHeight", 0);
int dpi = intent.getIntExtra("mDpi", 0);
MediaProjectionManager mediaProjectionManager =
(MediaProjectionManager) getSystemService(Context.MEDIA_PROJECTION_SERVICE);
MediaProjection projection = mediaProjectionManager.getMediaProjection(resultCode, data);
// 获取截屏文件的门路
String filePath = captureScreen(projection, width, height, dpi, this);
return super.onStartCommand(intent, flags, startId);
}
/**
* 获取截屏
*
* @param projection projection
* @param width width
* @param height height
* @param dpi dpi
* @param context context
* @return 返回截屏文件门路
*/
public static String captureScreen(MediaProjection projection, int width, int height, int dpi, Context context) {Log.d(TAG, "screenShot:");
Bitmap bitmap = null;
// 获取 ImageReader 实例
@SuppressLint("WrongConstant")
ImageReader imageReader = ImageReader.newInstance(width, height, PixelFormat.RGBA_8888, 2);
// 获取虚构显示器 VirtualDisplay 的实例
VirtualDisplay display = projection.createVirtualDisplay("ScreenShot", width, height, dpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, imageReader.getSurface(), null, null);
try {SystemClock.sleep(STOP_TIME);
Image image = imageReader.acquireLatestImage();
Image.Plane[] planes = image.getPlanes();
ByteBuffer buffer = planes[0].getBuffer();
int pixelStride = planes[0].getPixelStride();
int rowStride = planes[0].getRowStride();
int rowPadding = rowStride - pixelStride * width;
bitmap = Bitmap.createBitmap(width + rowPadding / pixelStride, height, Bitmap.Config.ARGB_8888);
bitmap.copyPixelsFromBuffer(buffer);
image.close();} catch (Exception e) {e.printStackTrace();
} finally {if (imageReader != null) {imageReader.close();
}
if (projection != null) {projection.stop();
}
if (display != null) {display.release();
}
}
String outPath = "";
try {outPath = saveImage(bitmap, context);
} catch (IOException e) {e.printStackTrace();
}
return outPath;
}