The interaction of Java and Shell-scripts in Android

It happens that in my current project I wanted to implement the execution of shell-scripts directly from the code. In order to get in the swing of things, I suggest you read this article: Shell-scripting environment Android (in Russian but code examples pretty clear). The author of the article describes well the features of Shell-language, but I needed to execute both scripts and Java methods in the same code. Android_x86 was used as development environment. However, you can use the rooted phone (root access required). Scripts execution from Java is fairly simple:

/** 
* Run scripts in separate thread.
*
* @param command shell script.
*/
public void runCommand(final String command) {
// To avoid UI freezes run in thread
new Thread(new Runnable() {
public void run() {
OutputStream out = null;
InputStream in = null;
try {
// Send script into runtime process
Process child = Runtime.getRuntime().exec(command);
// Get input and output streams
out = child.getOutputStream();
in = child.getInputStream();
//Input stream can return anything
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in));
String line;
String result = "";
while ((line = bufferedReader.readLine()) != null)
result += line;
//Handle input stream returned message
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();
}

In Android_x86 scripts can be sent directly to the process, and they will be executed. If you use your phone, this line:

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

should be replaced by those here:

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

I do not know how you can explain it, but on the phone before running the script you have to run a shell environment. All other things are the same. As an example, let’s write a few shell-commands, which can then be combined into a script:

/** 
* Pause between commands
*
* @param i seconds
* @return command
*/
public static String doSleep(int i) {
return "adb shell 'sleep " + i + "' ;";
}
/**
* Swipe gesture
*
* @param x1 start point
* @param y1 start point
* @param x2 end point
* @param y2 end point
* @return command
*/
public static String doSwipe(int x1, int y1, int x2, int y2) {
return "adb shell input swipe " + x1 + " " + y1 + " " + x2 + " " + y2 + " ;";
}
/**
* Tap gesture
*
* @param x
* @param y
* @return command
*/
public static String doTap(int x, int y) {
return "adb shell input tap " + x + " " + y + " ;";
}
/**
* Input text into text field
*
* @param text text
* @return command
*/
public static String doInputText(String text) {
return "adb shell input text " + text + " ;";
}
/**
* Button click simulation
*
* @param keycode button code
* @return command
*/
public static String doInputKeyevent(int keycode) {
return "adb shell input keyevent " + keycode + " ;";
}
/**
* Message output (will be caught in input stream)
*
* @param message message
* @return command
*/
public static String echo(String message) {
return "echo '" + message + "' ;";
}

These commands can also be combined in different scripts:

/** 
* Example of the script
*
* @return script
*/
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("I Robot"))
.concat(doSleep(1))
.concat(doInputKeyevent(KeyEvent.KEYCODE_ENTER))
.concat(doSleep(1))
.concat(echo("SCRIPT_FINISHED"));
return command;
}

To call this script is very simple:

runCommand(sampleScript());

This script with an interval of 1 second do swipe first, then do tap, then enters text, emulates pressing the Enter key, and then sends a signal of completion. Now the fun part. This script will be performed in the background of a few seconds, because it has delays. By its completion in the input stream we get the message. In my example, I convert it to a string, and then call the method handleBashCommandsResult(result), which takes the message as an input parameter. In this method, the result can be compared to a constant, for example:

/** 
* Handle message returned by script(usually returned by echo statement)
*
* @param result message.
*/
private void handleBashCommandsResult(String result) {
if (result.contains("SCRIPT_FINISHED")) {
// Do something after sample script execution
} else if (.....){
// Do something after another script execution
} else {
// Do something default
}
}

That’s it. In handleBashCommandsResult method you can perform, for example, any check or/and start execution of one of several other scripts, depending on the results of this check. Anyway, I briefly describe how to do interaction of shell-scripts and Java code. Hopefully, somebody can find it useful for them. If there are any questions, I will try to answer you.

Translatiion of that article

Mobile developer, snowboarder, dog lover

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store