去年写过关于安卓运行 dex 的文章 https://testerhome.com/topics/9649
那时候觉得真是好东西。最近研究 minicap(C++),vysor(反射调用 screenshot)这些同屏工具,想造个轮子试试:dex+ 反射截屏。

原文在此:http://www.wanyor.com/index.php/2018/03/12/115.html

0x00.截屏核心代码:

参考安卓源码:

/**
反射大法调用Surface|SurfaceControl的screenshot方法
参考安卓源码:
sdk >  17: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/view/SurfaceControl.java
sdk <= 17: https://android.googlesource.com/platform/frameworks/base/+/android-4.2.2_r1.2/core/java/android/view/Surface.java
*/
public static Bitmap screecap(int screenWidth, int screenHeight){

  String surfaceClassName = " ";

  if (Build.VERSION.SDK_INT <= 17) {
    surfaceClassName = "android.view.Surface";
  } else {
    surfaceClassName = "android.view.SurfaceControl";
  }

  // 关键在于此处反射调用获取bitmap
  Bitmap bitmap = (Bitmap) Class.forName(surfaceClassName).getDeclaredMethod("screenshot", new Class[]{Integer.TYPE, Integer.TYPE})
                    .invoke(null, new Object[]{picWidth, picHeight});
  return bitmap;
}

0x01.bitmap 转换为图片

压缩 bitmap 为 jpg|png 图片,写入 sd 卡或其他合适路径即可。

// 关键代码,压缩mBitmap为不失真的jpg图片,写入fOut。
mBitmap.compress(Bitmap.CompressFormat.JPEG, 100, fOut);

0x02.拓展:浏览器看图

java 实现一个简单的 HTTP server,把图片 base64 编码, 嵌在 html 中自动刷新,然后使用 adb forward 重定向绑定到电脑的某一端口,浏览器访问。

//截屏转base64字符串
public static String cap2base64(){
    int picWidth = 1080;
    int picHeight = 1920;
    String result = "";

    System.out.println("Starting screen capture...");

    long startTime = System.currentTimeMillis();

    String surfaceClassName = " ";
    if (Build.VERSION.SDK_INT <= 17) {
        surfaceClassName = "android.view.Surface";
    } else {
        surfaceClassName = "android.view.SurfaceControl";
    }

    try {
        Bitmap bitmap;
        bitmap = (Bitmap) Class.forName(surfaceClassName).getDeclaredMethod("screenshot", new Class[]{Integer.TYPE, Integer.TYPE})
                .invoke(null, new Object[]{picWidth, picHeight});

        System.out.println(bitmap.getWidth() + "x" + bitmap.getHeight());
        System.out.println(bitmap.toString());

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);

        baos.flush();
        baos.close();

        byte[] bitmapBytes = baos.toByteArray();
        result = Base64.encodeToString(bitmapBytes, Base64.DEFAULT);

        long endTime = System.currentTimeMillis();
        System.out.println("Cost: " + (endTime - startTime) + "ms");
        System.out.println("Screen capture finished.");

    } catch (IllegalAccessException e) {
        System.out.println("1 error");
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        System.out.println("2 error");
        e.printStackTrace();
    } catch (NoSuchMethodException e) {
        System.out.println("3 error");
        e.printStackTrace();
    } catch (ClassNotFoundException e) {
        System.out.println("4 error");
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return result;
}

//http server
public void startServer(int port){
    try {
        try (ServerSocket ss = new ServerSocket(port)) {
            while (true) {
                Socket socket = ss.accept();

                PrintWriter pw = new PrintWriter(socket.getOutputStream());

                pw.println("HTTP/1.1 200 OK");
                pw.println("Content-type:text/html");
                pw.println();
                pw.println("<head>" +
                        "<meta charset=\"utf-8\"/>" +
                        "<meta http-equiv=\"refresh\" content=\"0.25\">" +
                        "<title>Android Screen Mirror</title>" +
                        "</head>");
                pw.println("<h2>A screen mirror tool for android by Wanyor.</h2>" );

                Utils u = new Utils();
                String imgBase64 = u.cap2base64();
                pw.println("<img src=\"data:image/png;base64," + imgBase64 + "\" width=\"480\" height=\"800\"/>");

                pw.flush();
                socket.close();
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

0x03.demo 尝鲜

点此下载:yocap.zip
运行方式:

0x04.完成


↙↙↙阅读原文可查看相关链接,并与作者交流