Android: Dex+反射实现截屏服务器
去年写过关于安卓运行dex的文章 https://testerhome.com/topics/9649
那时候觉得,哇,真是好东西。最近研究minicap(C++),vysor(反射调用screenshot)这些同屏工具,想造个轮子试试:dex+反射截屏。
0x00.截屏核心代码:
参考安卓源码:
- 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
/**
反射大法调用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卡或其他合适路径即可。
代码烂就不贴了,后面提供一个demo,可以尝试下
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();
}
}