Так сложилось, что в моём текущем проекте необходимо было реализовать выполнение 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/
Добавить комментарий