- How to run Java programs directly on Android (without creating an APK)
- A (not so) simple Hello World program
- Setting up the working directory
- Compiling and dexing the Java class
- Creating the startup shellscript
- Installing and running the (non-) app
- It works, but how do I get a Context?!
- Follow up articles
- Android как запустить java
- Возможные проблемы
- Запуск проекта
- Режим разработчика на телефоне
- Запуск приложения
How to run Java programs directly on Android (without creating an APK)
A step by step instruction for compiling a Java program into an Android executable and using ADB to run it.
When you want to create a system / commandline tool for Android, you have to write it in C(++)… or do you? TLDR; here’s the final proof of concept. Sticking with Java would have the benefit of avoiding all of the native ABI hassle and also being able to call into the Android runtime. So how do we do that?
A (not so) simple Hello World program
Let’s start with the Java program we want to run. In order to make it a bit more interesting (and because any useful program has dependencies), it won’t just print the obligatory “Hello World” message, but also use the Apache Commons CLI library to parse its commandline arguments:
package com.example; import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import org.apache.commons.cli.ParseException; public class HelloWorld public static void main(String[] args) throws ParseException Option version = new Option("v", "Print version"); Option help = new Option("h", "Print help"); Options options = new Options(); options.addOption(help); options.addOption(version); for (Option opt : new DefaultParser().parse(options, args).getOptions()) if (opt.equals(version)) String os = System.getProperty("os.arch"); System.out.println("Hello World (" + os + ") v0.1"); > if (opt.equals(help)) new HelpFormatter().printHelp("Hello World", options); > > > >
Setting up the working directory
We will have to manually run several commandline tools in the next step, assuming the following final directory structure:
. ├── android-sdk-linux │ └── build-tools │ └── 23.0.2 │ └── dx ├── bin │ └── com │ └── example │ └── HelloWorld.class ├── lib │ └── commons-cli-1.3.1.jar ├── src │ └── com │ └── example │ └── HelloWorld.java ├── helloworld.jar └── helloworld.sh
- Android SDK (either via Android Studio or the SDK Manager). NOTE: If you are an Android developer, you’ll have the Android SDK already installed. In that case, you don’t actually need to copy it to the working directory as long as you know the path to the dx tool.
- Apache Commons CLI library v1.3.1
Afterwards copy&paste the HelloWorld code from above into the source folder. You might also find my semantic version parser class useful later on (not required here, though).
Compiling and dexing the Java class
Next step is to compile the java class (keep in mind that Android is stuck with Java 7 — bytecode for later versions won’t work). In case you are not used to doing this outside of an IDE, here’s the command:
javac -source 1.7 -target 1.7 -d bin -cp lib/commons-cli-1.3.1.jar src/com/example/HelloWorld.java
Make sure the program compiled properly:
java -cp lib/commons-cli-1.3.1.jar:bin com.example.HelloWorld -h usage: Hello world -h Print help -v Print version
Android cannot run Java class files directly. They have to be converted to Dalvik’s DEX format first (yes, even if you are using ART):
./android-sdk-linux/build-tools/23.0.2/dx --output=helloworld.jar --dex ./bin lib/commons-cli-1.3.1.jar
NOTE: Android Build Tools v28.0.2 and later contain a dx upgrade, called d8 . The d8 tool can process Java 8 class files. I’ll stick with dx for backwards compatibility reasons here.
Creating the startup shellscript
Android does not have a (normal) JRE, so JAR files cannot be started the same way as on a PC. You need a shellscript wrapper to do this. Copy&paste the one below to the workspace.
base=/data/local/tmp/helloworld export CLASSPATH=$base/helloworld.jar export ANDROID_DATA=$base mkdir -p $base/dalvik-cache exec app_process $base com.example.HelloWorld "$@"
NOTE: DEX files can also be started directly using the dalvikvm command, but going through app_process gives us a pre-warmed VM from the Zygote process (it is also the method employed by framework commands like pm and am ).
Installing and running the (non-) app
Time to push everything to the device:
adb shell mkdir -p /data/local/tmp/helloworld adb push helloworld.jar /data/local/tmp/helloworld adb push helloworld.sh /data/local/tmp/helloworld adb shell chmod 777 /data/local/tmp/helloworld/helloworld.sh
Moment of truth (fingers crossed):
adb shell /data/local/tmp/helloworld/helloworld.sh -v Hello World (armv7l) v0.1
NOTE: Since nothing was installed into the system, getting rid of the program is simply done by deleting the directory again.
It works, but how do I get a Context?!
Contexts represent an environment that is associated with an app (which we explicitly did not build) and are also device dependant. They can only be created by the ActivityThread class (a hidden system class that you cannot instantiate). If you want to interact with the Android runtime, you have to talk to the system services directly through their Binder interfaces. But that’s a topic for another article.
Follow up articles
Android как запустить java
Теперь создадим первое приложение в среде Android Studio для операционной системы Android. Откроем Android Studio и на начальном экране выберем пункт New Project :
При создании проекта Android Studio вначале предложит нам выбрать шаблон проекта:
Android Studio предоставляет ряд шаблонов для различных ситуаций. Выберем в этом списке шаблон Empty Activity , который предосавляет самый простейший фукционал, необходимый для начала, и нажмем на кнопку Next .
После этого отобразится окно настроек нового проекта:
В окне создания нового проекта мы можем установить его начальные настройки:
- В поле Name вводится название приложения. Укажем в качестве имени название HelloApp
- В поле Package Name указывается имя пакета, где будет размещаться главный класс приложения. В данном случае для тестовых проектов это значение не играет ольшого значения, поэтому установим com.example.helloapp .
- В поле Save Location установливается расположение файлов проекта на жестком диске. Можно оставить значение по умолчанию.
- В поле Language в качестве языка программирования укажем Java (будьт внимательны, так как по умолчанию в этом поле стоит Kotlin)
- В поле Minimum SDK указывается самая минимальная поддерживаемая версия SDK. Оставим значение по умолчанию — API 21: Android 5.0 (Lollipop) , которая означает, что наше приложение можно будет запустить начиная с Android 5.0, а это 94% устройств. На более старых устройствах запустить будет нельзя. Стоит учитывать, что чем выше версия SDK, тем меньше диапазон поддерживаемых устройств.
Далее нажмем на кнопку Finish, и Android Studio создаст новый проект:
Вначале вкратце рассмотрим структуру проекта, что он уже имеет по умолчанию
Проект Android может состоять из различных модулей. По умолчанию, когда мы создаем проект, создается один модуль — app . Модуль имеет три подпапки:
- manifests : хранит файл манифеста AndroidManifest.xml , который описывает конфигурацию приложения и определяет каждый из компонентов данного приложения.
- java : хранит файлы кода на языке java, которые структурированы по отдельным пакетам. Так, в папке com.example.helloapp (название которого было указано на этапе создания проекта) имеется по умолчанию файл MainActivity.java с кодом на языке Java, который представляет класс MainActivity, запускаемый по умолчанию при старте приложения
- res : содержит используемые в приложении ресурсы. Все ресурсы разбиты на подпапки.
- папка drawable предназначена для хранения изображений, используемых в приложении
- папка layout предназначена для хранения файлов, определяющих графический интерфейс. По умолчанию здесь есть файл activity_main.xml , который определяет интерфейс для класса MainActivity в виде xml
- папки mipmap содержат файлы изображений, которые предназначены для создания иконки приложения при различных разрешениях экрана.
- папка values хранит различные xml-файлы, содержащие коллекции ресурсов — различных данных, которые применяются в приложении. По умолчанию здесь есть два файла и одна папка:
- файл colors.xml хранит описание цветов, используемых в приложении
- файл strings.xml содержит строковые ресурсы, используемые в приложении
- папки themes хранит две темы приложения — для светлую (дневную) и темную (ночную)
Отдельный элемент Gradle Scripts содержит ряд скриптов, которые используются при построении приложения.
Во всей этой структуре следует выделить файл MainActivity.java, который открыт в Android Studio и который содержит логику приложения и собственно с него начинается выполнение приложения. И также выделим файл activity_main.xml , который определяет графический интерфейс — по сути то, что увидит пользователь на своем смартфоне после загрузки приложения.
Возможные проблемы
Для создания приложения используется Java. А для построения приложения применяется инфраструктура Gradle. Однако текущая используемая версия Gradle может быть несовместима с выбранной по умолчанию версией JDK. И в этом случае Android Studio может отображать ошибки, например, ошибку Unsupported class file major version 61 :
Эта ошибка говорит о том, что версия JDK 17 несовместима с текущей версией Gradle. И надо использовать меньшую версию.
Для решения этой проблемы перейдем в студии к меню File ->Settings (на MacOS это пункт Android Studio -> Preferences )
Затем в открывшемся окне настроек перейдем к пункту меню Build, Execution, Deployment -> Build Tools -> Gradle и далее найдем поле Gradle JDK , где изменим версию JDK. Она должна иметь версию 11 и выше. Как правило, вместе с Android Studio устанавливается и поддерживаемая версия JDK — на данный момент это JDK 11. И ее можно выбрать в списке JDK:
Наиболее оптимальный пункт для выбора версий JDK, которая идет вместе с Android Studio, называется Embedded JDK version. . Как видно на скриншоте, это версия 11, но при последующих обновлениях Android Studio эта версия может измениться.
После сделанных изменений сначала нажмем на кнопку Apply , а затем на кнопку OK . И повторим запуск проекта.
Запуск проекта
Созданный выше проект уже содержит некоторый примитивный функционал. Правда, этот функционал почти ничего не делает, только выводит на экран строку «Hello world!». Тем не менее это уже фактически приложение, которое мы можем запустить.
Для запуска и тестирования приложения мы можем использовать эмуляторы или реальные устройства. Но в идеале лучше тестировать на реальных устройствах. К тому же эмуляторы требуют больших аппаратных ресурсов, и не каждый компьютер может потянуть требования эмуляторов. А для использования мобильного устройства для тестирования может потребоваться разве что установить необходимый драйвер.
Режим разработчика на телефоне
По умолчанию опции разработчика на смартфонах скрыты. Чтобы сделать их доступными, надо зайти в Settings > About phone (Настройки > О телефоне) (в Android 8 это в Settings > System > About phone (Настройки > Система > О телефоне) ) и семь раз нажать Build Number (Номер сборки) .
Теперь необходимо включить отладку по USB. Для этого перейдем в Settings > System > Advanced > Developer options или Настройки > Система > Дополнительно > Для разработчиков (в Android 8 это в Settings > System > Developer options или Настройки > Система > Для разработчиков ).
И включим возможность отладки по USB:
Запуск приложения
Подключим устройство с ОС Android (если мы тестируем на реальном устройстве) и запустим проект, нажав на зеленую стрелочку на панели инструментов.
Выберем устройство и нажмем на кнопку OK. И после запуска мы увидим наше приложение на экране устройства: