Взаимодейтсвие Java и Shell-скриптов в Android

от автора

Так сложилось, что в моём текущем проекте необходимо было реализовать выполнение shell-скриптов прямиком из кода.

Для того, чтобы войти в курс дела, советую вам прочитать эту статью: Shell-скриптинг в среде Android

В ней очень хорошо описаны возможности языка Shell, однако мне помимо самих скриптов нужно было выполнять методы Java.

В процессе разработки был использован образ Android_x86. Однако можно использовать рутованный телефон (наличие прав суперпользователя обязательно).

Сами скрипты из Java выполняются довольно просто:

    /**      * Метод выполняет скрипты shell в отдельном потоке.      *      * @param command shell скрипт.      */     public void runCommand(final String command) {          // Чтобы не вис интерфейс, запускаем в другом потоке         new Thread(new Runnable() {             public void run() {                 OutputStream out = null;                 InputStream in = null;                 try {                    // Отправляем скрипт в рантайм процесс                     Process child = Runtime.getRuntime().exec(command);                     // Выходной и входной потоки                     out = child.getOutputStream();                     in = child.getInputStream();                      //Входной поток может что-нибудь вернуть                     BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));                     String line;                     String result = "";                     while ((line = bufferedReader.readLine()) != null)                         result += line;                      //Обработка того, что он вернул                     handleBashCommandsResult(result);                  } catch (IOException e) {                                  e.printStackTrace();                 } finally {                     if (in != null) {                         try {                             in.close();                         } catch (IOException e) {                             e.printStackTrace();                         }                     }                     if (out != null) {                         try {                             out.flush();                             out.close();                         } catch (IOException e) {                             e.printStackTrace();                         }                     }                 }             }         }).start();     } 

В Android_x86 можно отправлять скрипты сразу в процесс, и они буду выполняться. Если использовать телефон, то вот эту строчку:

Process child = Runtime.getRuntime().exec(command); 

нужно заменить на вот эти:

Process child = Runtime.getRuntime().exec(new String[] { "su", "-c", "system/bin/sh" }); DataOutputStream stdin = new DataOutputStream(child.getOutputStream()); //Скрипт stdin.writeBytes(command); 

Я не знаю, чем можно объяснить это, но на телефоне перед выполнением скриптов нужно запустить командную оболочку. В остальном всё одинаково.

Для примера напишем несколько shell-команд, которые потом можно будет собирать в скрипты:

  /**      * Пауза между командами      *      * @param i секунд      * @return команда      */     public static String doSleep(int i) {         return "adb shell 'sleep " + i + "' ;";     }     /**      * Жест свайп      *      * @param x1 откуда      * @param y1 откуда      * @param x2 куда      * @param y2 куда      * @return команда      */     public static String doSwipe(int x1, int y1, int x2, int y2) {         return "adb shell input swipe " + x1 + " " + y1 + " " + x2 + " " + y2 + " ;";     }      /**      * Жест тап      *      * @param x      * @param y      * @return команда      */     public static String doTap(int x, int y) {         return "adb shell input tap " + x + " " + y + " ;";     }      /**      * Ввод текста в поле ввода      *      * @param text текст      * @return команда      */     public static String doInputText(String text) {         return "adb shell input text " + text + " ;";     }      /**      * Нажатие кнопки      *      * @param keycode код кнопки      * @return команда      */     public static String doInputKeyevent(int keycode) {         return "adb shell input keyevent " + keycode + " ;";     }      /**      * Вывод сообщения (которое потом во входном потоке ловится)      *      * @param message сообщение      * @return команда      */     public static String echo(String message) {         return "echo '" + message + "' ;";     }  

Данные команды можно также комбинировать в различные скрипты:

    /**      * Пример скрипта      *      * @return скрипт      */     public static String sampleScript(){         String command = "";          command = command                 .concat(doSwipe(100, 200, 100, 500))                 .concat(doSleep(1))                 .concat(doTap(100, 150))                 .concat(doSleep(1))                 .concat(doInputText("Я скрипт"))                 .concat(doSleep(1))                 .concat(doInputKeyevent(KeyEvent.KEYCODE_ENTER))                 .concat(doSleep(1))                 .concat(echo("SCRIPT_FINISHED"));         return command;     } 

Вызвать данный скрипт очень просто:

runCommand(sampleScript()); 

Данный скрипт с интервалом в 1 секунду сначала свайпает, затем тапает, затем вводит текст, эмулирует нажатие клавиши Enter и затем посылает сообщение с сигналом о завершении.

Теперь самое интересное. Данный скрипт будет выполняться в фоне несколько секунд, поскольку в нём выставлены задержки. По его завершению во входном потоке будет это сообщение. В моём примере я преобразовываю его в строку, и после этого вызываю метод handleBashCommandsResult(result), который в качестве входного параметра и принимает эту строку. В этом методе результат можно сравнить

 /**      * Обработка того, что вернул скрипт (возвращает он обычно ключевое слово командой echo)      *      * @param result ответ скрипта.      */     private void handleBashCommandsResult(String result) {          if (result.contains("SCRIPT_FINISHED")) {             //Здесь делаем всё что хотели сделать после завершение скрипта         } else if (.....){            //А вот здесь можно сделать что-нибудь после другого скрипта         } else {           //А вот здесь можно сделать всё остальное         } 

На этом в общем то и всё. В методе handleBashCommandsResult можно выполнить, например, какие-нибудь проверки и запустить выполнение одного из нескольких других скриптов, в зависимости от результатов этой проверки. Так или иначе, я кратко описал, как наладить взаимодейтвие shell-скриптов и Java кода, что в общем-то и хотел.

Надеюсь, кому-нибудь это может пригодиться. Если остались какие-либо вопросы, я постараюсь вам ответить.

ссылка на оригинал статьи http://habrahabr.ru/post/264135/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *