繼續在網上搜尋安卓按鍵模拟(其實那時都不知道用什麼關鍵字好了,能想到的關鍵字都用遍了,但是搜尋出來的結果,都是之前提到的那幾個依賴源碼環境和系統權限的方案)。發現有很多介紹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;