Preface
SurfaceControl.screenshot()
It is the system's screenshot method. It belongs to the system API and is not open to users. Therefore, if you want to use it, you need the system's signature ( platform.keystore
file) to call it.
On higher versions of Android (for example android 11
), if there is no system signature, even if reflection is used, a method cannot be found exception will be reported. However, if there is a system signature, just call it directly.
Old way to use
Many tutorials on the Internet show old calling methods, which are no longer applicable in higher versions, as follows:
- Screenshot using reflection call
//获取屏幕尺寸
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
float[] dims = {
mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
//调用screenshot()
try {
Class<?> demo = Class.forName("android.view.SurfaceControl");
Method method = demo.getDeclaredMethod("screenshot", int.class,int.class);
mScreenBitmap = (Bitmap) method.invoke(null,(int) dims[0],(int) dims[1]);
} catch (Exception e) {
e.printStackTrace();
}
//显示bitmap
ImageView image = findViewById(R.id.image);
image.setImageBitmap(mScreenBitmap);
- Directly call the screenshot method to take a screenshot
//获取屏幕尺寸
DisplayMetrics mDisplayMetrics = new DisplayMetrics();
float[] dims = {
mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels};
//调用screenshot()
Bitmap mScreenBitmap = SurfaceControl.screenshot((int) dims[0],(int) dims[1]);
//显示bitmap
ImageView image = findViewById(R.id.image);
image.setImageBitmap(mScreenBitmap);
New ways to use
In later versions of Android, screenshot(width, height)
the method has been cancelled, so the method of only passing in two int values does not work .
Among the remaining screenshot() construction parameters, screenshot(Rect sourceCrop, int width, int height, int rotation)
this method is the most convenient to use.
The parameter description is as follows:
parameter | effect |
---|---|
sourceCrop | The portion of the screen to be captured in a bitmap; the caller can pass in this if no cropping is required new Rect() . |
width | Returns the desired width of the bitmap; the original screen will be scaled down to this size; the caller can pass in this if scaling is not required 0 . |
height | Returns the desired height of the bitmap; the original screen will be scaled down to this size; the caller can pass in this if scaling is not required 0 . |
rotation | Apply a custom clockwise rotation to the screenshot, ie Surface.ROTION_0,90,180,270 . By default SurfaceFlinger will always take screenshots in its original portrait orientation, so this is useful for returning screenshots that are independent of device orientation |
Therefore, on the new android system, we can write like this:
//调用screenshot()
//参数传入默认的,表示直接截全屏并且不缩放,不裁剪,不旋转
Bitmap mScreenBitmap = SurfaceControl.screenshot(new Rect(), 0, 0, Surface.ROTATION_0);
//显示bitmap
ImageView image = findViewById(R.id.image);
image.setImageBitmap(mScreenBitmap);
Since this method does not depend on Activity, it can be used to achieve the effect of background screenshots . However, it should be noted that calling this method requires the system's signature ( platform.keystore
), or addingandroid:sharedUserId="android.uid.system"
Solution to screenshot() always returning null
If no error is reported after you call it, but the returned value bitmap
is always null
, it may be a permissions issue. The solution is as follows:
- increasing
AndroidManifest.xml
_android:sharedUserId="android.uid.system"
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.xxx"
android:sharedUserId="android.uid.system">
...
- If you don’t want to turn the app into a system app, you can
AndroidManifest.xml
add separate permissions in
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.xxx">
<!-- 增加此权限 -->
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
...
Just use one of the above two methods .