android屏幕共享及远程控制原理

来源:互联网 发布:ubuntu解压缩命令 编辑:程序博客网 时间:2024/05/21 11:25

今天用了下Vysor,可以实现屏幕共享和远程控制,并且不需要root,而且可以兼容所有版本Android,功能很是强大,反编译了,下面是根据Vysor源码精简的功能。

demo看这  https://github.com/android-notes/androidScreenShareAndControl

import android.graphics.Bitmap;import android.graphics.Point;import android.hardware.input.InputManager;import android.os.Build;import android.os.Handler;import android.os.SystemClock;import android.support.v4.view.InputDeviceCompat;import android.view.InputEvent;import android.view.KeyEvent;import android.view.MotionEvent;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/** * Created by wanjian on 2017/4/4. */public class Main {    private static InputManager im;    private static Method injectInputEventMethod;    private static long downTime;    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, FileNotFoundException {        if ("screenshot".equals(args[0])) {            screenShot();            return;        }        initEvent();        if ("home".equals(args[0])) {            System.out.println("home");            pressHome();            return;        }        if ("touch".equals(args[0])) {            System.out.println("slide");            slideScreen();            return;        }        if ("back".equals(args[0])) {            System.out.println("back");            back();            return;        }    }    private static void screenShot() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, FileNotFoundException {        System.out.println("started screenshot");        Point size = new Point();        size.x = 1080;        size.y = 1920;        String surfaceClassName;        if (Build.VERSION.SDK_INT <= 17) {            surfaceClassName = "android.view.Surface";        } else {            surfaceClassName = "android.view.SurfaceControl";        }        Bitmap b = (Bitmap) Class.forName(surfaceClassName).getDeclaredMethod("screenshot", new Class[]{Integer.TYPE, Integer.TYPE}).invoke(null, new Object[]{Integer.valueOf(size.x), Integer.valueOf(size.y)});        System.out.println(b);        File file = new File("/sdcard/myscreenshot");        if (!file.exists()) {            file.mkdirs();        }        b.compress(Bitmap.CompressFormat.JPEG, 60, new FileOutputStream(new File(file, System.currentTimeMillis() + ".jpg")));        System.out.println("finished   " + file.getAbsolutePath());    }    private static void back() throws InvocationTargetException, IllegalAccessException {        sendKeyEvent(im, injectInputEventMethod, InputDeviceCompat.SOURCE_KEYBOARD, 4, false);    }    private static void slideScreen() throws InvocationTargetException, IllegalAccessException {        final float clientX = 900;        final float clientY = 200;        touchDown(clientX, clientY);        final Handler handler = new Handler();        handler.postDelayed(new Runnable() {            int i = 0;            float mClientX = clientX;            @Override            public void run() {                if (i++ > 300) {                    try {                        touchUp(mClientX, clientY);                    } catch (Exception e) {                        e.printStackTrace();                    }                    return;                }                mClientX -= 3;                try {                    touchMove(mClientX, clientY);                } catch (Exception e) {                    e.printStackTrace();                }                handler.postDelayed(this, 10);            }        }, 10);    }    private static void touchUp(float clientX, float clientY) throws InvocationTargetException, IllegalAccessException {        injectMotionEvent(im, injectInputEventMethod, InputDeviceCompat.SOURCE_TOUCHSCREEN, 1, downTime, SystemClock.uptimeMillis() - downTime, clientX, clientY, 1.0f);    }    private static void touchMove(float clientX, float clientY) throws InvocationTargetException, IllegalAccessException {        injectMotionEvent(im, injectInputEventMethod, InputDeviceCompat.SOURCE_TOUCHSCREEN, 2, downTime, SystemClock.uptimeMillis() - downTime, clientX, clientY, 1.0f);    }    private static void touchDown(float clientX, float clientY) throws InvocationTargetException, IllegalAccessException {        downTime = SystemClock.uptimeMillis();        injectMotionEvent(im, injectInputEventMethod, InputDeviceCompat.SOURCE_TOUCHSCREEN, 0, downTime, downTime, clientX, clientY, 1.0f);    }    private static void pressHome() throws InvocationTargetException, IllegalAccessException {        //home键        sendKeyEvent(im, injectInputEventMethod, InputDeviceCompat.SOURCE_KEYBOARD, 3, false);    }    private static void initEvent() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {        im = (InputManager) InputManager.class.getDeclaredMethod("getInstance", new Class[0]).invoke(null, new Object[0]);        MotionEvent.class.getDeclaredMethod("obtain", new Class[0]).setAccessible(true);        injectInputEventMethod = InputManager.class.getMethod("injectInputEvent", new Class[]{InputEvent.class, Integer.TYPE});    }    private static void injectMotionEvent(InputManager im, Method injectInputEventMethod, int inputSource, int action, long downTime, long eventTime, float x, float y, float pressure) throws InvocationTargetException, IllegalAccessException {        MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, x, y, pressure, 1.0f, 0, 1.0f, 1.0f, 0, 0);        event.setSource(inputSource);        injectInputEventMethod.invoke(im, new Object[]{event, Integer.valueOf(0)});    }    private static void injectKeyEvent(InputManager im, Method injectInputEventMethod, KeyEvent event) throws InvocationTargetException, IllegalAccessException {        injectInputEventMethod.invoke(im, new Object[]{event, Integer.valueOf(0)});    }    private static void sendKeyEvent(InputManager im, Method injectInputEventMethod, int inputSource, int keyCode, boolean shift) throws InvocationTargetException, IllegalAccessException {        long now = SystemClock.uptimeMillis();        int meta = shift ? 1 : 0;        injectKeyEvent(im, injectInputEventMethod, new KeyEvent(now, now, 0, keyCode, 0, meta, -1, 0, 0, inputSource));        injectKeyEvent(im, injectInputEventMethod, new KeyEvent(now, now, 1, keyCode, 0, meta, -1, 0, 0, inputSource));    }}



首先把这端代码编译成class文件,然后转成dex文件

dx --dex --output=Main.dex  Main.class

把转换好的dex文件发送到手机上

adb push Main.dex /sdcard/Main.dex

进入shell

adb shell

执行命令

export CLASSPATH=/sdcard/Main.dex 

执行截屏命令,执行后会放到/sdcard/myscreenshot文件夹下,vysor就是通过不停的截屏实现的屏幕共享

exec app_process /sdcard Main screenshot

执行按下home按键

exec app_process /sdcard Main home

执行按下返回按键

exec app_process /sdcard Main back

执行触屏事件

exec app_process /sdcard Main touch


完整命令如下:

MGJwanjian:sss wanjian$ dx --dex --output=Main.dex  Main.classMGJwanjian:sss wanjian$ adb push Main.dex /sdcard/Main.dex [100%] /sdcard/Main.dex MGJwanjian:sss wanjian$ adb shellshell@mx5:/ $ export CLASSPATH=/sdcard/Main.dex shell@mx5:/ $ exec app_process /sdcard Main screenshotstarted screenshotandroid.graphics.Bitmap@13c1ffa9finished   /sdcard/myscreenshot MGJwanjian:sss wanjian$ adb shellshell@mx5:/ $ export CLASSPATH=/sdcard/Main.dex shell@mx5:/ $ exec app_process /sdcard Main homehome MGJwanjian:sss wanjian$ adb shellshell@mx5:/ $ export CLASSPATH=/sdcard/Main.dex shell@mx5:/ $ exec app_process /sdcard Main backback MGJwanjian:sss wanjian$ adb shellshell@mx5:/ $ export CLASSPATH=/sdcard/Main.dex shell@mx5:/ $ exec app_process /sdcard Main touchslide MGJwanjian:sss wanjian$ adb shellshell@mx5:/ $ export CLASSPATH=/sdcard/Main.dex shell@mx5:/ $ exec app_process /sdcard Main touchslide 



补:关于如何把java文件打包成class文件


最简单的方式:
在android studio中右击com.wanjian.puppet.Main这个文件,选择 run Main.main(),编译后的class文件就会自动保存到  
androidScreenShareAndControl/shareandcontrollib/build/intermediates/classes/debug 这个目录中 




方式2:
把 android sdk目录下的android.jar和supportv4.jar拷贝到   
androidScreenShareAndControl/shareandcontrollib/src/main/java
目录下,同时在这个目录下新建classes文件夹,用于保存编译后的class文件,并把命令行切换到这个目录
执行如下命令,其中android.jar和support-v4-23.4.0-sources.jar 是android sdk中的jar包,一个在platforms/android-xx文件夹下,一个在extras/android/m2repository/com/android/support/support-v4下
中间用:分割,windows的话需要用;分割
javac -cp android.jar:support-v4-23.4.0-sources.jar:./  com/wanjian/puppet/Main.java  -d classes
这样就会在classes文件夹中生成class文件了(JDK版本不能太高,不然会提示 unsupported class file version 52.0)



1 0
原创粉丝点击