静默截屏功能,支持android12系统,需要系统签名,根据需要在AndroidManifest中配置以下权限和声明:
android:sharedUserId="android.uid.system"
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
<uses-permission android:name="android.permission.CAPTURE_SECURE_VIDEO_OUTPUT" />
主要代码:
package com.boeyu.test;
import android.app.Service;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
import android.hardware.display.VirtualDisplay;
import android.media.Image;
import android.media.ImageReader;
import android.os.Build;
import android.os.IBinder;
import android.os.Process;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.WindowManager;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
public class ScreenUtils {
private static final String TAG = "WALX";
/**
* 静默截屏,需要权限android.permission.READ_FRAME_BUFFER
*
* @return
*/
public static Bitmap getScreenshot(Context context) {
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
if (Build.VERSION.SDK_INT >= 31) {
//android12以上
try {
Class SurfaceControl = Class.forName("android.view.SurfaceControl");
Class DisplayCaptureArgs = Class.forName("android.view.SurfaceControl$DisplayCaptureArgs");
Class Builder = Class.forName("android.view.SurfaceControl$DisplayCaptureArgs$Builder");
IBinder displayToken = (IBinder) SurfaceControl.getMethod("getInternalDisplayToken").invoke(null);
Constructor CBuilder = Builder.getConstructor(IBinder.class);
Object mBuilder = CBuilder.newInstance(displayToken);
Object mDisplayCaptureArgs = Builder.getMethod("build").invoke(mBuilder);
Method captureDisplay = SurfaceControl.getMethod("captureDisplay", DisplayCaptureArgs);
captureDisplay.setAccessible(true);
Object mScreenshotHardwareBuffer = captureDisplay.invoke(null, mDisplayCaptureArgs);
return (Bitmap) mScreenshotHardwareBuffer.getClass().getMethod("asBitmap").invoke(mScreenshotHardwareBuffer);
} catch (Throwable e) {
Log.e(TAG, e.toString());
}
} else {
try {
Class c = Class.forName("android.view.SurfaceControl");
Method method = c.getMethod("screenshot", Rect.class, int.class, int.class, int.class);
return (Bitmap) method.invoke(c, new Rect(), 0, 0, wm.getDefaultDisplay().getRotation());
} catch (Throwable e) {
Log.e(TAG, e.toString());
}
}
return null;
}
/**
* 方法二,需要权限android.permission.CAPTURE_VIDEO_OUTPUT和android.permission.CAPTURE_SECURE_VIDEO_OUTPUT
* @param context
* @return
*/
public static Bitmap getScreenshot2(Context context){
VirtualDisplay virtualDisplay = null;
ImageReader reader = null;
Image image = null;
try {
DisplayMetrics metrics = new DisplayMetrics();
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
wm.getDefaultDisplay().getRealMetrics(metrics);
DisplayManager dm = (DisplayManager) context.getSystemService(Service.DISPLAY_SERVICE);
reader = ImageReader.newInstance(metrics.widthPixels, metrics.heightPixels, PixelFormat.RGBA_8888, 1);
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR | DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC | DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
if (Process.myUid() == Process.SYSTEM_UID) {
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
}
virtualDisplay = dm.createVirtualDisplay("capture_screen", metrics.widthPixels, metrics.heightPixels, metrics.densityDpi, reader.getSurface(), flags);
int count = 0;
while (image == null) {
Thread.sleep(50);
image = reader.acquireLatestImage();
if (++count > 10) {
break;
}
}
if (image != null) {
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);
return bitmap;
}
} catch (Throwable e) {
Log.e(TAG, e.toString());
} finally {
try {
if (image != null) {
image.close();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (virtualDisplay != null) {
virtualDisplay.release();
}
} catch (Exception e) {
e.printStackTrace();
}
try {
if (reader != null) {
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}