原理简介:
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、火狐 、谷歌  、搜狗等");
}

标签: none

已有 2 条评论

  1. 桂大大 桂大大

    你好,源码能开源吗,学习下

    1. 留下微信,发给你

评论已关闭