1. 背景
老大最近有個需求要捕獲一些東西(具體不能細說),然后在需求的最關鍵的一個點就歸結到要點擊一下別的APP的一個指定位置.
在網上搜索安卓按鍵模擬。用了很多方式都不太好,最后鎖定了使用ADB調試的方案,向手機發送按鍵事件。剛好之前做過在Root權限下,用Java調用安卓底層的Linux Shell,然后執行pm指令使用Shell調用ADB指令.
使用Java執行Runtime.getRuntime().exec("su").getOutputStream()
,獲取了一個具有Root權限的Process的輸出流對象,向其中寫入字符串即可以Root權限被Shell執行,ADB模擬按鍵的指令為 “input keyevent keyCode”,keyCode為按鍵的鍵值,例如KeyEvent.KEYCODE_VOLUME_UP表示音量加。 至於觸屏或鼠標事件,只要調用相應的ADB指令即可。但是有一點問題,就是反應速度非常慢,尤其是連續模擬多個按鍵的時候,甚至會死機。而按鍵精靈運行的就相當流暢,我又開始好奇按鍵精靈是怎么實現的。 后來終於還是找到了原因,模擬按鍵時,不應每次都調用Runtime.getRuntime().exec(“su”),因為每次調用這個代碼的時候,都會獲取Runtime實例,並且執行”su”請求Root權限,反應就會很慢(我的理解是相當於每次都新開一個命令行窗口);而應該只是在一開始執行一次,並獲取一個OutputStream實例,后來每次執行一條Shell指令,只需向其中寫入相應字符串,這樣就快了很多。 下面貼出可用的代碼。要求設備已經Root,不需要其他任何特殊權限或簽名。由於用的是ADB指令,兼容性也不會有太大問題。首次運行程序時(其實也就是執行Runtime.exec(“su”)的時候),會請求Root權限。
/** * 用root權限執行Linux下的Shell指令 * */
public class RootShell {
private OutputStream os;
/** * 執行shell指令 * * @param cmd * 指令 */
public final void exec(String cmd) {
try {
if (os == null) {
os = Runtime.getRuntime().exec("su").getOutputStream();
}
os.write(cmd.getBytes());
os.flush();
} catch (Exception e) {
e.printStackTrace();
}
}
/** * 后台模擬全局按鍵 * * @param keyCode * 鍵值 */
public final void simulateKey(int keyCode) {
exec("input keyevent " + keyCode + "\n");
}
}