天天看點

安卓使用Root權限實作背景模拟全局按鍵、觸屏事件方法(類似按鍵精靈)

繼續在網上搜尋安卓按鍵模拟(其實那時都不知道用什麼關鍵字好了,能想到的關鍵字都用遍了,但是搜尋出來的結果,都是之前提到的那幾個依賴源碼環境和系統權限的方案)。發現有很多介紹ADB調試,向手機發送按鍵事件的文章。剛好之前做過在Root權限下,用Java調用安卓底層的Linux Shell,然後執行pm指令進行APK的安裝解除安裝。這時我突發奇想,能否用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權限。

寫這篇文章的主要目的,并不是要強調這件事的難度,也不隻是為了提出問題的解決方案(那樣就沒必要寫前面那麼多過程了)。而是想把我解決問題的過程完整的寫出來,對我而言算是一個記錄,對讀者而言,沒準能從中找到一些東西。

解決這個問題之後,後來意外的發現,這個問題其實有人已經解決了,并且發了部落格。不幸的是,那篇部落格被大量使用前兩種思路的部落格掩埋了,當時我怎麼也沒找到。這篇部落格位址在此:

<a href="http://blog.csdn.net/aminfo/article/details/7785975" target="_blank">http://blog.csdn.net/aminfo/article/details/7785975</a>

順便說明一點,這篇部落格中作者提到的缺點:反應速度較慢。前面提到我也越到了同樣的問題,也已經給出了解決方案。

(标注了原文連結的文章除外)

android模拟按鍵問題總結[使用IWindowManager.injectKeyEvent方法]

<a href="http://blog.csdn.net/xudongdong99/article/details/8857173" target="_blank">http://blog.csdn.net/xudongdong99/article/details/8857173</a>

Android中使用隐藏API(大量圖解)  

<a href="http://163liufuliang.blog.163.com/blog/static/331651862013119114431760/" target="_blank">http://163liufuliang.blog.163.com/blog/static/331651862013119114431760/</a>

通過Runtime實作,代碼如下:

try  

{  

    String keyCommand = "input keyevent " + KeyEvent.KEYCODE_MENU;  

    Runtime runtime = Runtime.getRuntime();  

    Process proc = runtime.exec(keyCommand);  

}  

catch (IOException e)  

    // TODO Auto-generated catch block  

    e.printStackTrace();  

這個代碼是模拟菜單鍵,模拟其它按鍵隻需将KeyEvent.KEYCODE_MENU替換成其它鍵值。

缺點:反應速度較慢

以下附帶各KeyCode值:

KEYCODE_UNKNOWN=0;   

KEYCODE_SOFT_LEFT=1;   

KEYCODE_SOFT_RIGHT=2;   

KEYCODE_HOME=3;   

KEYCODE_BACK=4;   

KEYCODE_CALL=5;   

KEYCODE_ENDCALL=6;   

KEYCODE_0=7;   

KEYCODE_1=8;   

KEYCODE_2=9;   

KEYCODE_3=10;   

KEYCODE_4=11;   

KEYCODE_5=12;   

KEYCODE_6=13;   

KEYCODE_7=14;   

KEYCODE_8=15;   

KEYCODE_9=16;   

KEYCODE_STAR=17;   

KEYCODE_POUND=18;   

KEYCODE_DPAD_UP=19;   

KEYCODE_DPAD_DOWN=20;   

KEYCODE_DPAD_LEFT=21;   

KEYCODE_DPAD_RIGHT=22;   

KEYCODE_DPAD_CENTER=23;   

KEYCODE_VOLUME_UP=24;   

KEYCODE_VOLUME_DOWN=25;   

KEYCODE_POWER=26;   

KEYCODE_CAMERA=27;   

KEYCODE_CLEAR=28;   

KEYCODE_A=29;   

KEYCODE_B=30;   

KEYCODE_C=31;   

KEYCODE_D=32;   

KEYCODE_E=33;   

KEYCODE_F=34;   

KEYCODE_G=35;   

KEYCODE_H=36;   

KEYCODE_I=37;   

KEYCODE_J=38;   

KEYCODE_K=39;   

KEYCODE_L=40;   

KEYCODE_M=41;   

KEYCODE_N=42;   

KEYCODE_O=43;   

KEYCODE_P=44;   

KEYCODE_Q=45;   

KEYCODE_R=46;   

KEYCODE_S=47;   

KEYCODE_T=48;   

KEYCODE_U=49;   

KEYCODE_V=50;   

KEYCODE_W=51;   

KEYCODE_X=52;   

KEYCODE_Y=53;   

KEYCODE_Z=54;   

KEYCODE_COMMA=55;   

KEYCODE_PERIOD=56;   

KEYCODE_ALT_LEFT=57;   

KEYCODE_ALT_RIGHT=58;   

KEYCODE_SHIFT_LEFT=59;   

KEYCODE_SHIFT_RIGHT=60;   

KEYCODE_TAB=61;   

KEYCODE_SPACE=62;   

KEYCODE_SYM=63;   

KEYCODE_EXPLORER=64;   

KEYCODE_ENVELOPE=65;   

KEYCODE_ENTER=66;   

KEYCODE_DEL=67;   

KEYCODE_GRAVE=68;   

KEYCODE_MINUS=69;   

KEYCODE_EQUALS=70;   

KEYCODE_LEFT_BRACKET=71;   

KEYCODE_RIGHT_BRACKET=72;   

KEYCODE_BACKSLASH=73;   

KEYCODE_SEMICOLON=74;   

KEYCODE_APOSTROPHE=75;   

KEYCODE_SLASH=76;   

KEYCODE_AT=77;   

KEYCODE_NUM=78;   

KEYCODE_HEADSETHOOK=79;   

KEYCODE_FOCUS=80;//*Camera*focus   

KEYCODE_PLUS=81;   

KEYCODE_MENU=82;   

KEYCODE_NOTIFICATION=83;   

KEYCODE_SEARCH=84;   

KEYCODE_MEDIA_PLAY_PAUSE=85;   

KEYCODE_MEDIA_STOP=86;   

KEYCODE_MEDIA_NEXT=87;   

KEYCODE_MEDIA_PREVIOUS=88;   

KEYCODE_MEDIA_REWIND=89;   

KEYCODE_MEDIA_FAST_FORWARD=90;   

KEYCODE_MUTE=91;