Skip to content

Commit 6278055

Browse files
author
朱辉\harry
committed
添加push文件的功能
1 parent c82e165 commit 6278055

21 files changed

Lines changed: 3729 additions & 128 deletions

‎README.md‎

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
# AndroidControl
22
这是一款实时控制Android手机的工具
33

4-
### 包含内容
4+
**欢迎提交`issue`,如果它对你有帮助,点个`Star`哟**
55

6-
* 网页端😀
7-
* 客户端😀
8-
* 服务端😀
9-
10-
### 已实现功能
11-
* 显示手机屏幕
12-
* 可对手机进行操作
13-
* 单点触摸
14-
* 滑动
15-
* 设置屏幕的缩放比例
16-
* 设置屏幕的旋转角度
17-
* 键盘映射 (需要修改,目前使用adb命令,速度太慢了)
18-
* 文字输入 (需要修改,目前使用adb命令,速度太慢了)
6+
## What?
197

8+
* 查看手机的实时屏幕
9+
* 查看参数设置
10+
* 设置屏幕的缩放比例
11+
* 设置屏幕的旋转角度
12+
* 操作手机
13+
* 单点触摸
14+
* 滑动
15+
* 键盘输入
16+
* 文字输入
17+
* 上传文件到手机
2018

2119
![demo](docs/demo.gif)
2220

23-
### 使用方法
21+
## Run demo
2422

2523
1. 使用Gradle构建项目: `gradle jar`
2624
2. 进入到生成的目录:`cd build/libs`
@@ -33,31 +31,22 @@
3331
* 测试的手机需要打开Debug模式
3432
* 某些手机需要特别开启虚拟按键的权限
3533

36-
### 日后
34+
## For Developers
35+
36+
本项目的核心是: `LocalServer` `RemoteServer` `RemoteClient`,`web`文件夹内只是DEMO
37+
38+
你可以根据`docs/接口说明`封装一个操作的界面
39+
40+
## Features
41+
3742
* 帧数限制,用户可自定义帧数
38-
* 画面清晰度,旋转,缩放设定
3943
* 群控功能,可以控制多台设备
44+
* 模拟实体按键
4045
* 操作映射,对一台机器的操作映射到多台机器
4146
* 操作录制、运行(使用脚本语言,js|lua|python语言的支持,可能只实现js)
4247
* 服务器支持
4348
* 流压缩(h264)
4449

45-
### 技术栈介绍
46-
* 核心模块
47-
* Java
48-
* C++
49-
* Android NDK
50-
* Android ADB
51-
* Android ddmlib
52-
* Websocket
53-
* ... add
54-
* 网页端
55-
* html5/css3/js/jquery
56-
* bootstrap
57-
* ... add
58-
* 客户端
59-
* ... add
60-
61-
### 感谢
50+
### Thanks
6251
* `minicap` [https://github.com/openstf/minicap](https://github.com/openstf/minicap)
6352
* `minitouch` [https://github.com/openstf/minitouch](https://github.com/openstf/minitouch)

‎docs/接口说明-暂定.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ shot://{sn:"SerialNumber"}
1818
minicap://open|close
1919
minitouch://open|close
2020
keyevent://key
21+
push://{name:"filename", path:"devicepath"}
22+
message://... // 你想发送的消息
2123

2224
以下的暂未确定
2325
device://

‎src/main/java/com/yeetor/Main.java‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
package com.yeetor;
22

33
import com.neovisionaries.ws.client.WebSocketException;
4-
import com.yeetor.androidcontrol.RemoteClient;
5-
import com.yeetor.androidcontrol.LocalServer;
6-
import com.yeetor.androidcontrol.RemoteServer;
4+
import com.yeetor.androidcontrol.client.RemoteClient;
5+
import com.yeetor.androidcontrol.server.LocalServer;
6+
import com.yeetor.androidcontrol.server.RemoteServer;
77

8-
import java.io.IOException;
98
import java.security.InvalidParameterException;
109

1110

‎src/main/java/com/yeetor/androidcontrol/Command.java‎

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ public enum Schem {
2121
INPUT("input"),
2222
SHOT("shot"),
2323
MINICAP("minicap"),
24-
MINITOUCH("minitouch");
24+
MINITOUCH("minitouch"),
25+
PUSH("push"),
26+
MESSAGE("message");
2527

2628
private String schemStr;
2729

@@ -79,14 +81,20 @@ public Command(String command) throws InvalidParameterException {
7981
case "minitouch":
8082
schem = Schem.MINITOUCH;
8183
break;
84+
case "push":
85+
schem = Schem.PUSH;
86+
break;
87+
case "message":
88+
schem = Schem.MESSAGE;
89+
break;
8290
default:
8391
throw new InvalidParameterException(command + " 未知的schem");
8492
}
8593

8694
String contentStr = command.substring(splitIndex + 3);
8795

88-
// minitouch keyevent,此消息不是json格式。其他都为json键值对
89-
if (!schem.equals(Schem.TOUCH) && !schem.equals(Schem.KEYEVENT) && !schem.equals(Schem.INPUT) && !schem.equals(Schem.MINICAP) && !schem.equals(Schem.MINITOUCH)) {
96+
// 此消息不是json格式。其他都为json键值对
97+
if (!schem.equals(Schem.TOUCH) && !schem.equals(Schem.KEYEVENT) && !schem.equals(Schem.INPUT) && !schem.equals(Schem.MINICAP) && !schem.equals(Schem.MINITOUCH) && !schem.equals(Schem.MESSAGE)) {
9098
try {
9199
this.content = parseContentJson(contentStr);
92100
} catch (JSONException e) {

‎src/main/java/com/yeetor/androidcontrol/Protocol.java‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.yeetor.androidcontrol;
22

3+
import com.yeetor.androidcontrol.client.LocalClient;
34
import com.yeetor.minicap.Minicap;
45
import com.yeetor.minitouch.Minitouch;
56
import io.netty.channel.ChannelHandlerContext;

‎src/main/java/com/yeetor/androidcontrol/WSSocketHandler.java‎

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.yeetor.androidcontrol;
22

3+
import com.neovisionaries.ws.client.WebSocket;
4+
import com.neovisionaries.ws.client.WebSocketFactory;
35
import io.netty.buffer.ByteBuf;
46
import io.netty.buffer.Unpooled;
57
import io.netty.channel.ChannelFuture;
@@ -9,6 +11,7 @@
911
import io.netty.handler.codec.http.*;
1012
import io.netty.handler.codec.http.websocketx.*;
1113
import io.netty.util.CharsetUtil;
14+
import org.apache.commons.lang3.ArrayUtils;
1215

1316
/**
1417
* Created by harry on 2017/4/18.
@@ -17,6 +20,7 @@ public class WSSocketHandler extends SimpleChannelInboundHandler<Object> {
1720

1821
WebSocketServerHandshaker handshaker;
1922
WebsocketEvent event;
23+
byte binaryCache[] = new byte[0];
2024

2125
public WSSocketHandler(WebsocketEvent event) {
2226
this.event = event;
@@ -63,24 +67,19 @@ private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame fra
6367
if (event != null) {
6468
event.onTextMessage(ctx, ((TextWebSocketFrame) frame).text());
6569
}
66-
} else if (frame instanceof BinaryWebSocketFrame) {
70+
} else if (frame instanceof BinaryWebSocketFrame || frame instanceof ContinuationWebSocketFrame) {
6771
if (event != null) {
68-
69-
ByteBuf byteBuf = ((BinaryWebSocketFrame) frame).content();
72+
ByteBuf byteBuf = frame.content();
7073
byte[] bytes = new byte[byteBuf.readableBytes()];
7174
byteBuf.getBytes(0, bytes);
72-
event.onBinaryMessage(ctx, bytes);
75+
binaryCache = ArrayUtils.addAll(binaryCache, bytes);
76+
if (frame.isFinalFragment()) {
77+
byte[] b = binaryCache;
78+
binaryCache = new byte[0];
79+
event.onBinaryMessage(ctx, b);
80+
}
7381
}
7482
}
75-
76-
77-
78-
// 返回应答消息
79-
// String request = ((TextWebSocketFrame) frame).text();
80-
// System.out.println("服务端收到:" + request);
81-
// TextWebSocketFrame tws = new TextWebSocketFrame(new Date().toString()
82-
// + ctx.channel().id() + ":" + request);
83-
// ctx.channel().writeAndFlush(tws);
8483
}
8584

8685
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
@@ -98,7 +97,7 @@ private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
9897
return;
9998
}
10099
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
101-
null, null, false, Integer.MAX_VALUE);
100+
null, null, true, Integer.MAX_VALUE, true);
102101
handshaker = wsFactory.newHandshaker(req);
103102
if (handshaker == null) {
104103
WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel());

‎src/main/java/com/yeetor/androidcontrol/WebsocketEvent.java‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
* Created by harry on 2017/4/18.
88
*/
99
public abstract class WebsocketEvent {
10-
abstract void onConnect(ChannelHandlerContext ctx);
11-
abstract void onDisconnect(ChannelHandlerContext ctx);
12-
abstract void onTextMessage(ChannelHandlerContext ctx, String text);
13-
abstract void onBinaryMessage(ChannelHandlerContext ctx, byte[] data);
14-
DefaultFullHttpResponse onHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
10+
public abstract void onConnect(ChannelHandlerContext ctx);
11+
public abstract void onDisconnect(ChannelHandlerContext ctx);
12+
public abstract void onTextMessage(ChannelHandlerContext ctx, String text);
13+
public abstract void onBinaryMessage(ChannelHandlerContext ctx, byte[] data);
14+
public DefaultFullHttpResponse onHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) {
1515
return null;
1616
}
1717
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.yeetor.androidcontrol.client;
2+
3+
/**
4+
* Created by harry on 2017/5/10.
5+
*/
6+
public class BaseClient {
7+
}

src/main/java/com/yeetor/androidcontrol/LocalClient.java renamed to src/main/java/com/yeetor/androidcontrol/client/LocalClient.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
package com.yeetor.androidcontrol;
1+
package com.yeetor.androidcontrol.client;
22

33
import com.alibaba.fastjson.JSONObject;
4+
import com.android.ddmlib.AdbCommandRejectedException;
5+
import com.android.ddmlib.IDevice;
6+
import com.android.ddmlib.SyncException;
7+
import com.android.ddmlib.TimeoutException;
8+
import com.yeetor.adb.AdbServer;
9+
import com.yeetor.androidcontrol.Command;
10+
import com.yeetor.androidcontrol.Protocol;
411
import com.yeetor.minicap.Banner;
512
import com.yeetor.minicap.Minicap;
613
import com.yeetor.minicap.MinicapListener;
@@ -11,13 +18,15 @@
1118
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
1219
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
1320

21+
import java.io.File;
22+
import java.io.IOException;
1423
import java.util.concurrent.BlockingQueue;
1524
import java.util.concurrent.LinkedBlockingQueue;
1625

1726
/**
1827
* Created by harry on 2017/4/19.
1928
*/
20-
public class LocalClient implements MinicapListener, MinitouchListener {
29+
public class LocalClient extends BaseClient implements MinicapListener, MinitouchListener {
2130
static final int DATA_TIMEOUT = 100; //ms
2231
private boolean isWaitting = false;
2332
private BlockingQueue<ImageData> dataQueue = new LinkedBlockingQueue<ImageData>();
@@ -45,6 +54,9 @@ public void executeCommand(ChannelHandlerContext ctx, Command command) {
4554
case INPUT:
4655
inputCommand(command);
4756
break;
57+
case PUSH:
58+
pushCommand(command);
59+
break;
4860
}
4961
}
5062

@@ -186,6 +198,20 @@ private void inputCommand(Command command) {
186198
protocol.getMinitouch().inputText(str);
187199
}
188200

201+
private void pushCommand(Command command) {
202+
String name = command.getString("name", null);
203+
String path = command.getString("path", null);
204+
205+
IDevice device = AdbServer.server().getDevice(protocol.getSn());
206+
try {
207+
device.pushFile(new File(name).getAbsolutePath(), path + "/" + name);
208+
} catch (Exception e) {
209+
}
210+
if (protocol != null) {
211+
protocol.getBroswerSocket().channel().writeAndFlush(new TextWebSocketFrame("message://pushfile success"));
212+
}
213+
}
214+
189215
private void startMinicap(Command command) {
190216
if (protocol.getMinicap() != null) {
191217
protocol.getMinicap().kill();

0 commit comments

Comments
 (0)