1. 程式人生 > >Android模擬點選螢幕,實現按鍵精靈點選螢幕功能

Android模擬點選螢幕,實現按鍵精靈點選螢幕功能

我在實現安卓模擬點選螢幕固定位置時嘗試了很多方法,碰了不少壁,現在我將我實現的方法分享給大家,以及我嘗試過的方法也分享給大家,讓大家在開發的路上少走些彎路。

首先我嘗試用安卓輔助功能AccessibilityService類實現模擬螢幕點選,但是這個類只能找到頁面的控制元件,然後對控制元件進行模擬點選,不能實現對螢幕的某個位置進行點選,這個方法失敗後我就試了另一種Instrumentation方法,這種方法確實可以點選螢幕上任何位置,而且點選事件可以生效,但是退出程式就不能進行了,程式出現錯誤,提示沒有INJECT_EVENTS許可權,但是加入INJECT_EVENTS許可權後,還是出錯,查了一下資料,說可以在新增android:sharedUserId="android.uid.system"獲取系統共享簽名,但是加入後生成的APK無法安裝的手機上。

使用Instrumentation方法點選手機螢幕的任何位置

import java.io.IOException;
 
import android.app.Instrumentation;
import android.os.SystemClock;
import android.util.Log;
import android.view.MotionEvent;
 
public class ThreadClass extends Thread {
    private int x,y;
    //400,689
    @Override
    public void run() {
        while(true)
        {            
            //利用ProcessBuilder執行shell命令
            /*String[] order = {
                    "input",
                    "tap",
                    "" + x,
                    "" + y
            };
            Log.d("點選位置", x+","+y);
            try {
                new ProcessBuilder(order).start();
            } catch (IOException e) {
                e.printStackTrace();
            }*/
            // 可以不用在 Activity 中增加任何處理,各 Activity 都可以響應 
             try {  
                Instrumentation inst = new Instrumentation();  
                inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(),   
                    MotionEvent.ACTION_DOWN, x, y, 0));  
                inst.sendPointerSync(MotionEvent.obtain(SystemClock.uptimeMillis(),SystemClock.uptimeMillis(),   
                    MotionEvent.ACTION_UP, x, y, 0));
                Log.d("點選位置", x+","+y);
             }catch(Exception e) {  
                 Log.e("Exception when sendPointerSync", e.toString());  
             }  
            //執行緒睡眠3s
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
 
    }
    public ThreadClass(int x,int y){
        this.x=x;
        this.y=y;
    }
}
其中x,y是需要點選的螢幕左邊,以左上角為原點的直角座標系統
加入INJECT_EVENTS許可權

<uses-permission android:name="android.permission.INJECT_EVENTS"/>
新增android:sharedUserId="android.uid.system"位置如下,寫安卓的應該都可以明白
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.clickservice"
    android:versionCode="1"
    android:versionName="1.0" 
    android:sharedUserId="android.uid.system"
    >

        為了解決這個錯誤,我按照網上說的方法進行,使用安卓簽名工具SignApk.jar對編譯的apk進行簽名,簽名後的APK還是無法安裝在手機上,還有一種解決這問題的方法就是使用android原始碼編譯,相信這種方法會讓大多數人無從下手,光將android原始碼編譯的環境搭配起來都不是一件容易的事,有興趣的可以嘗試一下這種方法,下面就步入我們今天要講的主題adb shell。
首先我們在windows下通過adb shell控制手機,在此之前,保證你的手機已經連線電腦,進入eclipse adt開發環境下的adb所在檔案目錄,以我的為例,路徑為..\adt-bundle-windows-x86-20130917\sdk\platform-tools,以下是我的目錄截圖,可以對著找到該目錄。


        在該目錄下,按下shift鍵後點擊滑鼠右鍵,在彈出視窗中選擇“在此處開啟命令視窗(W)”,也可以直接cmd進入這目錄,在命令視窗輸入:adb shell 進入adb shell命令狀態,此後就可以用shell命令控制你的手機了。

我在此就簡單介紹一些命令,要想詳細瞭解的去下面兩篇部落格

自己動手開發精簡版按鍵精靈

Android模擬螢幕點選事件

getevent -p 
檢視哪個裝置包含event 體系裡 寬(0035)和高(0036),那麼這個裝置就是我們的安卓手機,例如這裡的裝置名稱為/dev/input/event1


模擬傳送事件
getevent/sendevent是Android系統下的一個工具,可以模擬多種按鍵和觸屏操作,產生的是raw event,raw event經過event hub處理產生最終的gesture事件。getevent用於獲取當前系統input裝置的一些引數和實時事件的資料;sendevent用於傳送input事件,這倆命令的作用就是相當於解放了手,可以通過命令直接呼叫Linux底層來控制手機,工具的原始碼位於Android SDK的system/core/toolbox下(sendevent.c getevent.c)。

傳送鍵盤事件 
用法說明: 
adb shell input keyevent “value” 
input text 
input keyevent 
input tap 
input swipe 
如上,input後可以跟很多引數, text相當於輸入內容,keyevent相當於手機物理或是螢幕按鍵,tap相當於touch事件,swipe相當於滑動~~是不是很贊?先列舉 input keyevent 幾個比較常用的code值: 
input keyevent 3 // Home 
input keyevent 4 // Back 
input keyevent 19 //Up 
input keyevent 20 //Down 
input keyevent 21 //Left 
input keyevent 22 //Right 
input keyevent 23 //Select/Ok 
input keyevent 24 //Volume+ 
input keyevent 25 // Volume- 
input keyevent 82 // Menu 選單

附:input keyevent所對應全部key值:

KeyCode Keyevent Value

KEYCODE_MENU 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 
KEYCODE_PLUS 81 
KEYCODE_MENU 82 
KEYCODE_NOTIFICATION 83 
KEYCODE_SEARCH 84 
TAG_LAST_KEYCODE 85

通過以上的介紹你應該對adb shell命令有所瞭解了吧,但是如何用程式碼來實現呢,以下就是程式碼執行shell命令
/** 
 * 執行shell命令 
 *  
 * @param cmd 
 */  
private void execShellCmd(String cmd) {  
  
    try {  
        // 申請獲取root許可權,這一步很重要,不然會沒有作用  
        Process process = Runtime.getRuntime().exec("su");  
        // 獲取輸出流  
        OutputStream outputStream = process.getOutputStream();  
        DataOutputStream dataOutputStream = new DataOutputStream(  
                outputStream);  
        dataOutputStream.writeBytes(cmd);  
        dataOutputStream.flush();  
        dataOutputStream.close();  
        outputStream.close();  
    } catch (Throwable t) {  
        t.printStackTrace();  
    }  
}  

在想要執行的地方呼叫上面函式:
execShellCmd("getevent -p");  
execShellCmd("sendevent /dev/input/event1 1 158 1");  
execShellCmd("sendevent /dev/input/event1 1 158 0");  
execShellCmd("input keyevent 3");//home  
execShellCmd("input text  'helloworld!' ");  
execShellCmd("input tap 168 252");  
execShellCmd("input swipe 100 250 200 280");  

注意使用sendevent執行事件時,可以看到sendevent需要4個引數即:device,type,code,value。這些值可以由input子系統定義,也可以從getevent裡面獲取。type其實就是和getevent中的支援事件型別所對應的, value=1是按下,value=0是彈起,也就是說只有當兩個命令同時執行時命令才會生效,也就是下面兩句要先後一併執行
execShellCmd("sendevent /dev/input/event1 1 158 1");  
execShellCmd("sendevent /dev/input/event1 1 158 0"); 

如果要退出程式後,繼續執行模擬點選螢幕,只要寫一個後臺執行的Service掛在後臺執行即可,到此模擬點選手機螢幕的功能就實現了

本文章對應程式,實現按鍵精靈模擬點選原始碼:http://download.csdn.net/download/yuanhengzhw/10254876
--------------------- 
作者:浪遏飛舟之心亙 
來源:CSDN 
原文:https://blog.csdn.net/yuanhengzhw/article/details/70435626 
版權宣告:本文為博主原創文章,轉載請附上博文連結!