各位看官在讀完 sendevent 的介紹後有什麼感想呢?是不是覺得使用 sendevent 有點繁瑣?若用在模擬按鍵的操作上似乎還勉強能夠接受,但一旦要模擬觸控螢幕的操作,比如拖曳,則似乎有些累人。雖然這問題可藉由良好的封裝來解決,但本喵今天就來為各位看官出個蠢主意——山寨一個 Monkeyrunner 吧!!
其實 Monkeyrunner 之所以能夠模擬裝置的輸入是建立在 Monkey 這個隨機測試程式上的,也就是說 Monkeyrunner 提供的舉凡按下按鍵、點擊螢幕、拖曳等動作都僅是將相關的命令傳給 Monkey,因此若要做一個最簡單的類 Monkeyrunner 的程式,咱們只要自己和 Monkey 溝通便好。與 Monkey 的溝通流程如下:
順序 | 動作 | 說明 |
---|---|---|
1 | 建立 PC 端與 Android 端的連接埠映射 |
因 PC 上的程式無法與 Android 裝置上的程式直接通訊,所以必須建立一個連接埠映射,如此資料便可在 PC 上的連接埠與 Android 上的連接埠間互相傳輸。
Monkeyrunner 使用的連接埠為 12345,使用 adb forward <LOCAL> <REMOTE> 指令來映射: adb forward tcp:12345 tcp:12345 |
2 | 啟動 Monkey 以監聽連接埠 | adb shell "monkey --port 12345" |
3 | 建立與 Monkey 的 socket 連線 | 連線位址為本機端,即 127.0.0.1 |
4 | 模擬所需輸入 | |
5 | 關閉 socket 連線 | 關閉連線前記得結束 Monkey(送出 quit 命令)。 |
咱們以 C# 來實作一個弧形拖曳的模擬吧!
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace test_adb
{
class Program
{
const int PORT = 12345;
static Process s_monkeyProc;
static void Main(string[] args)
{
Forward();
RunMonkey();
BuildSocket();
RemoveForward();
Console.Write("\nEnter any key to exit.");
Console.ReadKey();
}
static void Forward()
{
var info = new ProcessStartInfo()
{
FileName = "adb.exe",
Arguments = "forward tcp:" + PORT + " tcp:" + PORT
};
var proc = new Process()
{
StartInfo = info
};
proc.Start();
proc.WaitForExit();
}
static void RemoveForward()
{
var info = new ProcessStartInfo()
{
FileName = "adb.exe",
Arguments = "forward --remove tcp:" + PORT
};
var proc = new Process()
{
StartInfo = info
};
proc.Start();
proc.WaitForExit();
}
static void RunMonkey()
{
new Thread(() =>
{
var info = new ProcessStartInfo()
{
FileName = "adb.exe",
Arguments = "shell \"monkey --port " + PORT + "\""
};
s_monkeyProc = new Process()
{
StartInfo = info
};
s_monkeyProc.Start();
}).Start();
}
static void BuildSocket()
{
Thread.Sleep(2000);
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var remote = new IPEndPoint(IPAddress.Parse("127.0.0.1"), PORT);
try
{
socket.Connect(remote);
Wake(socket);
TestActions(socket);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
Quit(socket);
socket.Shutdown(SocketShutdown.Both);
socket.Close();
if (!s_monkeyProc.HasExited)
{
Console.WriteLine("Monkey not terminated. Wait 5 sec.");
s_monkeyProc.WaitForExit(5000);
if (!s_monkeyProc.HasExited)
{
Console.WriteLine("Failed to terminate Monkey.");
s_monkeyProc.Kill();
}
}
Console.WriteLine(s_monkeyProc.ExitCode);
s_monkeyProc.Close();
}
}
static void TestActions(Socket socket)
{
int ox = 620;
int oy = 150;
int x = ox;
int y = oy;
int r = 360;
TouchDown(socket, x, y);
Thread.Sleep(1000);
for (int i = 0; i < 50; ++i)
{
x = ox - (int)(r * Math.Sin(i * Math.PI / 180));
y = oy + r - (int)(r * Math.Cos(i * Math.PI / 180));
TouchMove(socket, x, y);
Thread.Sleep(10);
}
TouchUp(socket, x, y);
}
static void Quit(Socket socket)
{
SendRequest(socket, "quit");
Thread.Sleep(1000);
}
static void Wake(Socket socket)
{
SendRequest(socket, "wake");
Thread.Sleep(1000);
}
static void TouchDown(Socket socket, int x, int y)
{
SendRequest(socket, "touch down " + x + " " + y);
}
static void TouchMove(Socket socket, int x, int y)
{
SendRequest(socket, "touch move " + x + " " + y);
}
static void TouchUp(Socket socket, int x, int y)
{
SendRequest(socket, "touch up " + x + " " + y);
}
static void SendRequest(Socket socket, string cmd)
{
Console.WriteLine("Send: " + cmd);
var request = Encoding.ASCII.GetBytes(cmd + "\n");
var response = new byte[32];
socket.Send(request);
int len = socket.Receive(response);
Console.WriteLine("Receive: " + Encoding.ASCII.GetString(response, 0, len));
}
}
}
「看起來很簡單嘛~那長按按鍵也沒問題吧!」那邊有位看官吆喝道!
「其實長按按鍵是做不到的,這大概是 Monkey 的設計問題吧。。」本喵怯怯地說道 >__<
「那自己和 Monkey 溝通有啥鳥用阿!!」台下看官爆出陣陣不滿!
「ㄟ。。本喵其實也不知道這有什麼用啦 = =a」
沒有留言:
張貼留言