场景:android11 java场景,前端为arkui-x,所以后端activity无view。

很多方面是使用activity来获取view进行截屏,直接pass。

1、使用Android 的 adb 命令来截屏,性能不行

参考如下:

Android后台截屏功能_安卓开发 后台截图-CSDN博客

    public String screenShot() {
        Log.i(TAG, "screenShot!");
        @SuppressLint("SdCardPath")
        String capFile = "/sdcard/AIUI/ocr/pic.png";
        String cmd = "screencap -p " + capFile;
        CmdUtils.fetchRoot(cmd);
        return capFile;
    }

CmdUtils.fetchRoot是使用root权限执行adb shell命令。

因为adb命令是采用screencap,保存到文件。过程中启动了一个独立进程。

后续流程再读取文件来使用,相当于绕了一些弯路。

在1280x720分辨率下,耗时800m左右。

2、screenshot截屏

有人推荐了SurfaceControl.screenshot()

参考如下:SurfaceControl.screenshot()用法 | SurfaceControl.screenshot()使用后返回null的解决方案-CSDN博客

1)坑1:帖子上的旧方法反射和直接调用,新方法直接调用都不行,猜测是android版本不同。

上网查询android11的SurfaceControl.screenshot的参数,介绍都是4个参数或五个参数,与新方法一致。

灵机一动,用旧方法的反射写法,结合新方法的四个参数,如下:

    public byte[] screenShot() {
        Log.i(TAG, "screenShot!");
        try {
            Class<?> demo = Class.forName("android.view.SurfaceControl");
            Method method = demo.getDeclaredMethod("screenshot", Rect.class, int.class, int.class, int.class);
            Bitmap tbitmap = (Bitmap) method.invoke(null, new Rect(), 0, 0, Surface.ROTATION_0);

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            tbitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
            return baos.toByteArray();
        } catch (Exception e) {
            e.printStackTrace();
            byte[] o = null;
            return o;
        }
    }

日志报错如下:

2024-10-18 17:02:28.963 10884-10884 OcrUtil                 com.example.helloworld               I  screenShot!
2024-10-18 17:02:28.965   183-199   SurfaceFlinger          surfaceflinger                       E  Permission Denial: can't read framebuffer pid=10884, uid=10125
2024-10-18 17:02:28.960 10884-10884 Thread-127              com.example.helloworld               W  type=1400 audit(0.0:32721): avc: granted { read } for name="if_inet6" dev="proc" ino=4026532556 scontext=u:r:platform_app:s0:c512,c768 tcontext=u:object_r:proc_net:s0 tclass=file app=com.example.helloworld
2024-10-18 17:02:28.965 10884-10884 SurfaceFlinger          com.example.helloworld               E  captureScreen failed to transact: -1
2024-10-18 17:02:28.966 10884-10884 SurfaceControl          com.example.helloworld               W  Failed to take screenshot
2024-10-18 17:02:28.966 10884-10884 System.err              com.example.helloworld               W  java.lang.NullPointerException: Attempt to invoke virtual method 'boolean android.graphics.Bitmap.compress(android.graphics.Bitmap$CompressFormat, int, java.io.OutputStream)' on a null object reference
2024-10-18 17:02:28.967 10884-10884 System.err              com.example.helloworld               W  	at com.example.helloworld.ocr.OcrUtil.screenShot2(OcrUtil.java:281)

说明是framebuffer权限问题。

2)坑2:增加系统签名manifest下android:sharedUserId="android.uid.system",结果不生效。

检查manifest文件,发现在作其他需求时,在application下已经加了android:sharedUserId="android.uid.system",怀疑有冲突,删除application下语句。测试成功。

多次测试,相同分辨率下,截屏时间在500ms-600ms。

更多推荐