Android: Java 和 Websocket 实现安卓真机操控
原理简介:
1、使用反射截图,压缩为webp格式图片,把图片编码为base64格式,通过websocket服务发送给前端,前端绘制出图片。
2、websocket服务器使用websocket库:Java-WebSocket-1.4.0-with-dependencies.jar。
3、事件转发也是走websocket,发送事件类型和相关参数,websocket服务做出对应动作。
ScreenCaptor反射截图关键方法:
public static Bitmap getScreencap(int screenWidth, int screenHeight) {
Bitmap bitmap = null;
String surfaceClassName;
ServiceManager serviceManager = new ServiceManager();
if (screenHeight == 0 || screenWidth ==0){
screenWidth = serviceManager.getDisplayManager().getDisplayInfo().getSize().getWidth();
screenHeight = serviceManager.getDisplayManager().getDisplayInfo().getSize().getHeight();
}
if (Build.VERSION.SDK_INT <= 17) {
surfaceClassName = "android.view.Surface";
} else {
surfaceClassName = "android.view.SurfaceControl";
}
try {
// api_level >= 27,截图方法:public static Bitmap screenshot(int width, int height) {}
if (Build.VERSION.SDK_INT <= 27) {
bitmap = (Bitmap) Class.forName(surfaceClassName).getDeclaredMethod("screenshot", new Class[]{Integer.TYPE, Integer.TYPE})
.invoke(null, new Object[]{screenWidth, screenHeight});
} else {
// 参考这里https://medium.com/@punpun/android-surfacecontrol-screenshot-changed-in-android-pie-9-0-8baf2c91a068
// api_level大于27,截图方法变为:public static Bitmap screenshot(Rect sourceCrop, int width, int height, int rotation) {}
Rect rect = new Rect(0, 0, 0, 0);
int rotation = serviceManager.getDisplayManager().getDisplayInfo().getRotation();
bitmap = (Bitmap) Class.forName(surfaceClassName).getDeclaredMethod("screenshot", new Class[]{Rect.class, Integer.TYPE, Integer.TYPE, Integer.TYPE})
.invoke(null, new Object[]{rect, screenWidth, screenHeight, rotation});
}
} catch (Throwable e) {
e.printStackTrace();
}
return bitmap;
}
websocket服务器,关键方法onMessage:
@Override
public void onMessage(WebSocket webSocket, String s) {
if (s.equals( "help")) {
String help = "screencap, keyevent, mouseevent";
webSocket.send(help);
}
else if(s.equals("screencap")){
String screencap = ScreenCaptor.getBase64Screencap();
webSocket.send(screencap);
}
else if(s.equals("keyevent")){
webSocket.send("keyevent cmd.");
}
else if(s.contains("mouseevent")) {
String[] cmds = s.split("#");
Input input = new Input();
int inputSource = InputDevice.SOURCE_TOUCHSCREEN;
input.sendTap(inputSource, Float.parseFloat(cmds[2]),
Float.parseFloat(cmds[3]));
webSocket.send("mouseevent success.");
} else{
webSocket.send("Unknown cmd: " + s);
}
}
前端js关键代码:
var screen = document.getElementById('screen');
var websocket = '';
var x = 0;
var y = 0;
var downTimestamp = 0;
var upTimestamp = 0;
if (window.WebSocket) {
websocket = new WebSocket(encodeURI('ws://localhost:8888'));
websocket.onopen = function() {
console.log('已连接');
};
websocket.onerror = function() {
console.log('连接发生错误');
alert("websocket连接失败")
};
websocket.onclose = function() {
console.log('已经断开连接');
};
// 消息接收
websocket.onmessage = function(message) {
websocket.send("screencap");
screen.src = message.data;
};
} else {
alert("该浏览器不支持websocket。<br/>建议使用高版本的浏览器,<br/>如 IE10、火狐 、谷歌 、搜狗等");
}
你好,源码能开源吗,学习下