During development of Android application, sometimes I want to write a small class and test its functions in a fashion similar to a normal desktop console program:
Read input from '
stdin' and write output to '
However, Android virtually requires all programs to be a GUI program. In order to fulfill the above needs, I decided to write a console-like program on Android which acts like normal desktop console: display a command prompt and let user issue commands to bring up a third-party program to execute.
As shown in the diagram, this
CmdConsole program consists of:
- Console GUI
- to forward user input to command dispatcher or the currently running custom console app
- to print output from currently running custom console app
- Command dispatcher (Run on its own thread)
- if user issues an internal command (e.g. 'ls', 'cd', 'del', etc), forward it to appropriate module to execute
- if user wants to run an external console app, ApkRunner is launched to execute it
- ApkRunner (Run on its own thread)
- brings up the custom console app to run
Screenshot 1: Console running built-in commands
Screenshot 2: Console running a 3rd party app
Console UI is very simple. On the top, you got an edit box to input command; on the top right is an 'ENTER' button; and finally below is the area like normal console to output text.
The text view which outputs text is actually a modified
ImageView. Its '
onDraw' method is overridden to draw the output text line by line.
It is a class (not shown in the diagram) to load a third party apk and retrieve the '
main' entry point method inside the apk for later execution. The magic to load the apk is performed by '
dalvik.system.DexClassLoader', which is a class inside the Android SDK. This class isn't difficult to use. Only a few function calls can load and retrieve the method of any class you want. The logic to retrieve the '
main' method resides in
ApkLoader.loadEntryPoint(). The '
main' method is then passed to
ApkRunner to execute.
One point to note here is: loading a third party apk by '
DexClassLoader' will generate a 'dex' file for caching purpose. It is not bad but when you want to run a newer version of the third party app and the original cached 'dex' file still exists, sometimes, not always, the class loader failed strangely. Because of this,
CmdConsole will remove the cached 'dex' file every time before the apk is loaded.
Writing a 3rd Party Console App
Let's start writing a console app so as to consolidate your experience with it. Here, I only list the steps to build a project by command line tools but it is perfectly OK to build a project by Eclipse.
- Create a project using android SDK script:
> android create project \
--target 3 \
--name MyHello \
--path ./MyHello \
--activity MyHelloActivity \
Activity class is useless. Just delete it.
Comment out the whole "
application" tag in "AndroidManifest.xml" as they are useless, too:
Create a class, say '
MyHello', with a
static method "
main(HashMap<Integer, Object> args)" and use the '
CmdApp' (a helper class in the source attached) to initialize the arguments passed in:
public class MyHello
public static void main(HashMap<Integer, Object> args)
CmdApp cmdApp = new CmdApp(args);
args' passed in is a hash table (constructed inside
ApkRunner before calling '
main') containing some environment variables useful to a console app. Please see appendix for the content of the hash table.
CmdApp' is a helper class, provided in the sample console apps, to retrieve the content inside '
args' and provide convenient functions (like reading a line from
stdin) to access and use the content. After initializing '
CmdApp', just write your console program as usual.
Delete all unnecessary resource files inside 'res'.
Create a file "res/raw/entrypoint.txt" with the following single-line content:
This states the class which has the entry point function "
build.properties' at the project root, add this line:
It is the root path where
com.sss.consolehelper.CmdApp resides, thus,
CmdApp can be found and built later on. (For Eclipse users, right click your project in 'Package Explorer' ? 'Build Path' ? 'Link Source ...' to add the linking.)
Compile the project by:
> ant debug
Put the resultant "apk" file to anywhere of the file system in the emulator/phone. I usually happen to put it at the root of the SD card. To put it there, just type:
> adb push MyHello.apk /sdcard/MyHello.apk
CmdConsole and run the apk as shown in the screenshot above:
> run /sdcard/MyHello.apk
> cd /sdcard
> run MyHello.apk
When running a 3rd party app, currently, 2 menu options can be selected:
Kill Running App
Actually, this option only sends a
java.lang.InterruptedException to the running app and so this does not ensure the running app can be killed. The '
InterruptedException' only breaks out functions like '
wait', blocking '
sleep' and '
If the running app does not hang on one of these functions or the app has a
catch statement that catches all exceptions, this option can't break your 3rd party app.
This one will call '
android.os.Process.killProcess' to kill
Arguments Passed to the Console App
The entry point '
main' method of a console app should be declared as:
public static void main(HashMap<Integer, Object> args)
The arguments passed in by '
args' is a hash table with the following content:
|array of command line arguments; the 0th element is the start of arguments (which is *NOT* the program name); may be
null if no arguments
stdin for the console program
stdout for the console program
stdout) encoding, which is "UTF-8" at present
It is recommended to use '
CmdApp' to indirectly access the content.
Available Internal Commands
CmdConsole can list the available commands and typing '
help [command]' will print a more detailed description of the command.
Currently available commands are:
AndroidManifest.xml of CmdConsole
Since the 3rd party console app is actually running in the context of
CmdConsole, thus, the 3rd party app is restricted by the permission set inside 'AndroidManifest.xml' of
CmdConsole only states the permissions of '
ACCESS_WIFI_STATE' and '
ACCESS_NETWORK_STATE'. You may want to add more if you want to write a 3rd party app with more access rights.
- 30th May, 2011: Initial post