自动化工具 Java 和 Websocket 实现安卓真机操控

甬力君 · 2019年11月26日 · 最后由 Blanke 回复于 2019年12月30日 · 1935 次阅读

demo 效果预览:

原理简介:
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、火狐 、谷歌  、搜狗等");
}
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 1 条回复 时间 点赞

感谢分享,demo 开源吗?谢谢

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册