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)
- android屏幕共享及远程控制原理
- Mac终端命令远程开启屏幕共享进行远程控制
- OS X通过屏幕共享 远程控制其他Mac(简单远程控制)
- 手机远程控制原理
- 远程控制原理
- 远程控制 远程监控软件屏幕实用技巧
- 远程连接及远程控制
- 使用WebRTC实现远程屏幕共享
- 使用WebRTC实现远程屏幕共享
- 使用WebRTC实现远程屏幕共享
- Android屏幕的控制
- Android屏幕控制
- android 屏幕旋转控制
- Android屏幕旋转控制
- android 屏幕亮度控制
- Android 屏幕透明度控制
- android-控制屏幕常亮不锁屏
- Android 屏幕控制
- Shiro Ajax请求没有权限返回JSON,没有登录返回JSON
- 【error】Tomcat启动报错com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector
- error 、 assert、xpcall
- spring queryForObject 错误org.springframework.dao.EmptyResultDataAccessException: Incorrect result siz
- MySQL查询执行步骤
- android屏幕共享及远程控制原理
- MySQL查询优化小结
- NOW~很少有人分享错误信息的解决方法,查阅百度都是几年前的
- 不仅仅是写代码,而是完成作品
- 51nod编辑距离问题
- PHP常用加密函数
- 【OpenCV图像处理】十五、图像空域滤波(上)
- 算法训练 比较字符串
- 二分——POJ 3579 Median