Привет мир, используя только Android SDK (без IDE)
Мои цели:
- Проверьте основные инструменты разработки на простой программе
- Разверните программу в полезное приложение
Я предпочитаю работать с небольшими независимыми инструментами, а не с IDE. Я предпочитаю кодировать в процедурном или императивном стиле (простая старая Java), а не в декларативном (XML).
Я установил отдельный Android SDK в соответствии с инструкциями. У меня есть необходимый минимум других инструментов (текстовый редактор, командная оболочка и JDK). Но единственные инструкции по запуску, которые я могу найти, связаны с Android Studio, Eclipse или другими IDE. Я не могу следовать за ними.
Как я могу написать программу на Java с моим текстовым редактором для отображения "Hello world" на устройстве Android? Как я могу проверить это с помощью эмулятора SDK? Пожалуйста, дайте мне инструкции.
5 ответов
Это инструкции, которые в итоге сработали для меня. Я получил их, деконструируя Ant-скрипт Google, на котором основан ответ Роба.
Следующее содержание взято из "Программирование Android без IDE" из документации по переполнению стека ( архивировано здесь); авторские права 2017 - pensono, Michael Allan, Cascal, Doron Behar, mnoronha и AndroidMechanic - Viral Patel; лицензируется в соответствии с CC BY-SA 3.0. Архив полного содержимого документации по переполнению стека можно найти по адресу archive.org, где этот пример индексируется по его идентификатору темы: 85, например: 9496.
Это минималистский пример Hello World, в котором используются только самые основные инструменты Android.
Требования и предположения
- Oracle JDK 1.7 или более поздняя версия
- Android SDK Tools (только инструменты командной строки)
Этот пример предполагает Linux. Возможно, вам придется настроить синтаксис для вашей собственной платформы.
Настройка Android SDK
После распаковки выпуска SDK:
Установите дополнительные пакеты с помощью менеджера SDK. Не использовать
android update sdk --no-ui
как указано в прилагаемом Readme.txt; он загружает около 30 ГБ ненужных файлов. Вместо этого используйте интерактивный менеджер SDKandroid sdk
чтобы получить рекомендуемый минимум пакетов.Добавьте следующие каталоги JDK и SDK к вашей переменной PATH. Это необязательно, но инструкции ниже предполагают это.
- JDK / бен
- SDK/ платформенные инструменты
- SDK/ инструменты
- SDK/ build-tools / LATEST (как установлено в шаге 1)
Создайте виртуальное устройство Android. Используйте интерактивный AVD Manager (
android avd
). Возможно, вам придется немного повозиться и поискать совет; инструкции на месте не всегда полезны.(Вы также можете использовать свое собственное устройство)
Запустите устройство:
emulator -avd DEVICE
Если экран устройства заблокирован, проведите пальцем, чтобы разблокировать его.
Оставьте его работающим, пока вы кодируете приложение.
Кодирование приложения
Перейдите в пустой рабочий каталог.
Сделайте исходный файл:
mkdir --parents src/dom/domain touch src/dom/domain/SayingHello.java
Содержание:
package dom.domain; import android.widget.TextView; public final class SayingHello extends android.app.Activity { protected @Override void onCreate( final android.os.Bundle activityState ) { super.onCreate( activityState ); final TextView textV = new TextView( SayingHello.this ); textV.setText( "Hello world" ); setContentView( textV ); } }
Добавьте манифест:
touch AndroidManifest.xml
Содержание:
<?xml version='1.0'?> <manifest xmlns:a='http://schemas.android.com/apk/res/android' package='dom.domain' a:versionCode='0' a:versionName='0'> <application a:label='Saying hello'> <activity a:name='dom.domain.SayingHello'> <intent-filter> <category a:name='android.intent.category.LAUNCHER'/> <action a:name='android.intent.action.MAIN'/> </intent-filter> </activity> </application> </manifest>
Создайте подкаталог для заявленных ресурсов:
mkdir res
Оставьте это пустым пока.
Создание кода
Создайте источник для объявлений ресурсов. Введите здесь правильный путь к вашему SDK и установленный API для сборки (например, "android-23"):
aapt package -f \ -I SDK/platforms/android-API/android.jar \ -J src -m \ -M AndroidManifest.xml -S res -v
Объявления ресурсов (описанные ниже) на самом деле являются необязательными. Между тем вышеуказанный вызов ничего не делает, если res/ все еще пуст.
Скомпилируйте исходный код в байт-код Java (.java → .class):
javac \ -bootclasspath SDK/platforms/android-API/android.jar \ -classpath src -source 1.7 -target 1.7 \ src/dom/domain/*.java
Переведите байт-код с Java на Android (.class → .dex):
Сначала используйте Jill (.class → .jayce):
java -jar SDK/build-tools/LATEST/jill.jar \ --output classes.jayce src
Затем Джек (.jayce → .dex):
java -jar SDK/build-tools/LATEST/jack.jar \ --import classes.jayce --output-dex .
Байт-код Android раньше назывался "исполняемый код Dalvik" и т. Д. "Dex".
Вы можете заменить шаги 11 и 12 одним звонком Джеку, если хотите; он может компилироваться непосредственно из исходного кода Java (.java → .dex). Но есть преимущества для компиляции с
javac
, Это более известный, лучше документированный и более широко применяемый инструмент.Упакуйте файлы ресурсов, включая манифест:
aapt package -f \ -F app.apkPart \ -I SDK/platforms/android-API/android.jar \ -M AndroidManifest.xml -S res -v
Это приводит к частичному файлу APK (пакет приложений Android).
Сделайте полный APK используя
ApkBuilder
инструмент:java -classpath SDK/tools/lib/sdklib.jar \ com.android.sdklib.build.ApkBuilderMain \ app.apkUnalign \ -d -f classes.dex -v -z app.apkPart
Он предупреждает: "ЭТОТ ИНСТРУМЕНТ УСТАРЕЛ. Смотрите --help для получения дополнительной информации". Если
--help
терпит неудачу сArrayIndexOutOfBoundsException
, затем вместо передачи аргументов:java -classpath SDK/tools/lib/sdklib.jar \ com.android.sdklib.build.ApkBuilderMain
Это объясняет, что CLI (
ApkBuilderMain
) устарела в пользу прямого вызова API Java (ApkBuilder
). (Если вы знаете, как это сделать из командной строки, обновите этот пример.)Оптимизация выравнивания данных APK ( рекомендуемая практика):
zipalign -f -v 4 app.apkUnalign app.apk
Установка и запуск
Установите приложение на устройство Android:
adb install -r app.apk
Запустите приложение:
adb shell am start -n dom.domain/.SayingHello
Надо бежать и поздороваться.
Это все. Вот что нужно, чтобы поздороваться с помощью основных инструментов Android.
Объявление ресурса
Этот раздел не является обязательным. Декларации ресурсов не требуются для простого приложения "hello world". Если они также не требуются для вашего приложения, вы можете несколько упростить сборку, пропустив шаг 10 и удалив ссылку на каталог res/ из шага 13.
В противном случае, вот краткий пример того, как объявить ресурс и как ссылаться на него.
Добавьте файл ресурса:
mkdir res/values touch res/values/values.xml
Содержание:
<?xml version='1.0'?> <resources> <string name='appLabel'>Saying hello</string> </resources>
Ссылка на ресурс из манифеста XML. Это декларативный стиль ссылки:
<!-- <application a:label='Saying hello'> --> <application a:label='@string/appLabel'>
Ссылка на тот же ресурс из источника Java. Это обязательная ссылка:
// v.setText( "Hello world" ); v.setText( "This app is called " + getResources().getString( R.string.appLabel ));
Протестируйте вышеуказанные модификации, перестроив, переустановив и повторно запустив приложение (шаги 10-17).
Он должен перезагрузиться и сказать: "Это приложение называется Saying Hello".
Удаление приложения
adb uninstall dom.domain
Смотрите также
- рабочий пример - рабочий скрипт сборки, который использует вышеуказанные команды
Во-первых, серьезно, даже не подумайте об использовании эмулятора. Если только вы не хотите подвергнуться ненужным пыткам. Для тех, кто не хочет иметь багаж IDE, эмулятор в 100 раз хуже. Получить устройство было бы советом по этому вопросу.
Вы не сможете отказаться от XML. Я понимаю и ценю тот импульс, который у меня был похожий. Однако я в конце концов полюбил это. Используйте стили много. Я бы порекомендовал использовать Android Studio. Он имеет отличный инструмент для разметки кода и разметки интерфейса.
Даже если вы хотите просто написать код из редактора, вы можете использовать Android Studio, чтобы сделать свой проект заглушкой. Это довольно хорошо в этом. Если вы этого не знали, в документах есть способ создания проекта с помощью командной строки (без использования AS): здесь это задокументировано.
Поскольку Джек и Джилл устарели, мне пришлось изменить несколько команд.
Installed the sdk,ndk in /a (the ndk is not used in this hello world)
the jdk in the system
and the android-tools-adb in the /usr/bin etc (this one contains adb and fastboot and phone definitions so that it can detect them)
added this to .bashrc
export JAVA_HOME=/usr/lib64/java
export ANDROID_HOME=/a
export ANDROID_PLATFORM=$ANDROID_HOME/platforms/android-23
export ANDROID_BUILD_TOOLS=$ANDROID_HOME/build-tools/28.0.0-rc1
export ANDROID_NDK=$ANDROID_HOME/ndk
export ANDROID_TOOLS=$ANDROID_HOME/tools # sdk tools
PATH=$PATH:$JAVA_HOME/bin:$ANDROID_HOME:$ANDROID_BUILD_TOOLS:$ANDROID_NDK:$ANDROID_TOOLS:$ANDROID_TOOLS/bin:$ANDROID_PLATFORM
---
sdkmanager --list
sdkmanager "platforms;android-23"
sdkmanager platform-tools
mkdir /a/prj
cd /a/prj
mkdir --parents src/dom/domain
vi src/dom/domain/SayingHello.java
package dom.domain;
import android.widget.TextView;
public final class SayingHello extends android.app.Activity
{
protected @Override void onCreate( final android.os.Bundle activityState )
{
super.onCreate( activityState );
final TextView textV = new TextView( SayingHello.this );
textV.setText( "Hello world" );
setContentView( textV );
}
}
vi AndroidManifest.xml
<?xml version='1.0'?>
<manifest xmlns:a='http://schemas.android.com/apk/res/android'
package='dom.domain' a:versionCode='0' a:versionName='0'>
<application a:label='Saying hello'>
<activity a:name='dom.domain.SayingHello'>
<intent-filter>
<category a:name='android.intent.category.LAUNCHER'/>
<action a:name='android.intent.action.MAIN'/>
</intent-filter>
</activity>
</application>
</manifest>
# this section is OPTIONAL , the hello world can run without any res
mkdir res/values -p
vi res/values/values.xml
<?xml version='1.0'?>
<resources>
<string name='appLabel'>Saying hello</string>
</resources>
# Reference the resource from the AndroidManifest.xml manifest.
vi AndroidManifest.xml
<!-- <application a:label='Saying hello'> --> <!-- edit this -->
<application a:label='@string/appLabel'>
vi src/dom/domain/SayingHello.java
// v.setText( "Hello world" ); // edit this
v.setText( "This app is called "
+ getResources().getString( R.string.appLabel ));
# end OPTIONAL section
vi buildprj # create a build script
#!/bin/bash
#Generate the source for the resource declarations.
aapt package -f \
-I $ANDROID_PLATFORM/android.jar \
-J src -m \
-M AndroidManifest.xml -S res -v
#Compile the source code to Java bytecode (.java ï¾ .class)
javac \
-bootclasspath $ANDROID_PLATFORM/android.jar \
-classpath src -source 1.7 -target 1.7 \
src/dom/domain/*.java
#Translate the bytecode from Java to Android (.class ï¾ .dex)
dx --dex --output="classes.dex" src
#Package up the resource files, including the manifest
aapt package -f -F app.apkPart -I $ANDROID_PLATFORM/android.jar \
-M AndroidManifest.xml -S res -v
#Make the full APK using the ApkBuilder tool:
CLASSPATH=$ANDROID_TOOLS/lib/* java \
com.android.sdklib.build.ApkBuilderMain app.apkUnalign \
-d -f classes.dex -v -z app.apkPart
#Optimize the data alignment of the APK (recommended practice https://developer.android.com/studio/command-line/zipalign.html ):
zipalign -f -v 4 app.apkUnalign app.apk
adb install -r app.apk
adb shell am start -n dom.domain/.SayingHello
echo "To uninstall the app: adb uninstall dom.domain"
# cleanup
rm app.apkPart app.apkUnalign classes.dex
find . -name "*.class" -exec rm {} +
find . -name "R.java" -exec rm {} +
./buildprj # run the build script
-----pitfalls I had fallen into----
java -classpath $ANDROID_TOOLS/lib/sdklib.jar \
com.android.sdklib.build.ApkBuilderMain \
app.apkUnalign \
-d -f classes.dex -v -z app.apkPart
it gave an error that didn't say "sdklib.jar doesn't exist/is not found"
Error: Could not find or load main class com.android.sdklib.build.ApkBuilderMain
... :(
cd /a/tools/lib/
ln -s sdklib-25.3.1.jar sdklib.jar
java -classpath $ANDROID_TOOLS/lib/sdklib.jar \
com.android.sdklib.build.ApkBuilderMain \
app.apkUnalign \
-d -f classes.dex -v -z app.apkPart
Exception in thread "main" java.lang.NoClassDefFoundError: com/android/prefs/AndroidLocatio
java -classpath $ANDROID_TOOLS/lib/sdklib.jar \
com.android.sdklib.build.ApkBuilderMain \
app.apkUnalign \
-d -f classes.dex -v -z app.apkPart --help
THIS TOOL IS DEPRECATED. See --help for more information.
Unknown argument: --help
Wow...
Anyway it turns out it 's just explaining that the CLI (ApkBuilderMain) is deprecated in favour of directly calling the Java API (ApkBuilder). If you know how to do that from the command line, please update this example. UPDATE:Actually it seems impossible to do that from the command line so that warning is a bit strange...
"If --help fails with an ArrayIndexOutOfBoundsException, then instead pass no arguments:
java -classpath SDK/tools/lib/sdklib.jar \
com.android.sdklib.build.ApkBuilderMain
" all right...
Очень полезный пост. Я сделал простой регулятор яркости, используя ваши очень хорошие инструкции. Просто хотелось бы выяснить аргументы только для одного Джека. Был в состоянии поместить все в одну директорию, кроме иконки, которую нужно было найти в res\drawable-hdpi.
javac -bootclasspath c:\android\SDK/platforms/android-19/android.jar -classpath . *.java
java -jar c:\android\SDK/build-tools/24.0.1/jill.jar --output classes.jayce .
java -jar c:\android\SDK/build-tools/24.0.1/jack.jar --import classes.jayce --output-dex .
aapt package -f -F app.apkPart -I c:\android\SDK/platforms/android-19/android.jar -M AndroidManifest.xml -S res -v
java -classpath c:\android\SDK/tools/lib/sdklib.jar com.android.sdklib.build.ApkBuilderMain app.apkUnalign -d -f classes.dex -v -z app.apkPart
zipalign -f -v 4 app.apkUnalign brite.apk
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dom.domain"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.WRITE_SETTINGS"></uses-permission>
<application
android:allowBackup="true"
android:icon="@drawable/slkimage"
android:label="brite" >
<activity
android:name="dom.domain.MainActivity"
android:label="brite" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Команда dx теперь недоступна, и Apk Builder необходимо настроить ключ. Это мои настройки...
Установки
Сначала вам понадобится комплект разработчика программного обеспечения (SDK), комплект разработчика Java (JDK) и файл ключа.
- Чтобы использовать SDK без IDE, загрузите его здесь .
- Распаковать
Command line tools
(напримерunzip commandlinetools-linux.zip
). - Переместить каталог
cmdline-tools
для удобного расположения и переименовать его вSDK
(напримерmv cmdline-tools ~/.android/SDK
). - Перейти к
SDK/bin
и запустить (см. примечание 1)
./sdkmanager --sdk_root=../ --list
./sdkmanager --sdk_root=../ "platforms;android-31"
./sdkmanager --sdk_root=../ platform-tools
./sdkmanager --sdk_root=../ "build-tools;31.0.0"
- Загрузите JDK версии 11 здесь (> 11 не работает для виртуальной машины Android Java).
- Распакуйте JDK в удобный каталог и переименуйте его в JDK (например,
unzip openjdk-11.zip ; mv jdk-11 ~/.android/JDK
). - Перейти к
JDK/bin
и сделать ключ с./keytool -genkey -keystore ~/.keystore -keyalg RSA
. - Создайте скрипт для компиляции ваших приложений. Например (см. примечание 2)
#!/bin/bash
# Script to compile a android application source.
# The argument of the scrit is the directory of the source code (e.g. `ac hello_world/`),
# this directory may be have the file `AndroidManifest.xml`, the `res` directory
# and subdirectories containing the java source files.
cd "$1"
# ###
# seting up the ambient variables
# ###
export JAVA_HOME="$HOME/.android/JDK"
export ANDROID_HOME="$HOME/.android/SDK"
export ANDROID_PLATFORM="$ANDROID_HOME/platforms/android-31"
export ANDROID_BUILD_TOOLS="$ANDROID_HOME/build-tools/31.0.0"
export ANDROID_TOOLS="$ANDROID_HOME/tools"
export PATH=$JAVA_HOME/bin:$ANDROID_BUILD_TOOLS:$ANDROID_TOOLS:$PATH
# ###
# Compile the code
# ###
# Compile the source code to Java bytecode (.java to .class)
javac -cp $ANDROID_PLATFORM/android.jar $(find . -name "*.java")
# Translate the bytecode from Java to Android (.class to .dex)
d8 --lib $ANDROID_PLATFORM/android.jar $(find . -name "*.class")
# Package up the resource files, including the manifest
aapt package -f \
-F app.apkPart \
-I $ANDROID_PLATFORM/android.jar \
-M AndroidManifest.xml \
-S res/
# Make the full APK using the `ApkBuilder` tool
CLASSPATH=$ANDROID_TOOLS/lib/* java \
com.android.sdklib.build.ApkBuilderMain app.apkUnalign \
-u -f classes.dex -z app.apkPart
# Optimize the data alignment of the APK
zipalign -f 4 app.apkUnalign app_aligned.apk
# Signer the APK
apksigner sign --ks ~/.keystore --out app.apk app_aligned.apk
# ###
# Remove generated files
# ###
rm app.apkUnalign
rm app_aligned.apk
rm app.apkPart
rm classes.dex
find . -name "*.class" -exec rm {} +
exit 0
- Поместите скрипт в каталог bin (например,
~/bin/ac
из/bin/ac
were — это имя сценария) и сделать его исполняемым (например,chmod 755 ~/ac
).
Заметки:
-
platforms;android-31
а такжеbuild-tools;31.0.0
скажите «Загрузить инструменты для API 31 Android», но вы можете загрузить другую версию, см. доступные версии с помощью./sdkmanager --sdk_root=../ --list | grep "platforms;android"
а также./sdkmanager --sdk_root=../ --list | grep "build-tools;"
. - Этот сценарий предполагает, что вы помещаете SDK и JDK в
~/.android/SDK
а также~/.android/JDK
и предположим, что вы загрузили инструменты для Android API 31.
Читать далее:
Кодирование
Вам нужны в основном два файла, и . В конце концов вам понадобятся ресурсы для более продвинутых программ в каталоге с именем
res
, для этого примера каталог res пуст.
Содержание
AndroidManifest.xml
похоже на следующее.
<?xml version='1.0'?>
<manifest xmlns:android='http://schemas.android.com/apk/res/android'
package='com.your_company.app'
android:versionCode='0'>
<application
android:label='App name'>
<activity
android:name='com.your_company.app.MainActivity'>
<intent-filter>
<category android:name='android.intent.category.LAUNCHER'/>
<action android:name='android.intent.action.MAIN'/>
</intent-filter>
</activity>
</application>
</manifest>
Содержание выглядит следующим образом.
package com.your_company.app;
import android.app.Activity;
import android.widget.TextView;
import android.os.Bundle;
public final class MainActivity extends Activity {
@Override
protected void onCreate(final Bundle activityState){
super.onCreate(activityState);
final TextView textV = new TextView(MainActivity.this);
textV.setText("Hello World");
setContentView( textV );
}
}
Распространено помещать файл
MainActivity.java
в каталоге под названием
src/com/your_company/app/
. Дерево файлов выглядит следующим образом.
hello_world/
|
|--- AndroidManifest.xml
|--- res/
|--- src/
|--- com/
|--- your_company/
|--- app/
|--- MainActivity.java
Предположим, что у вас есть команда, в которой вы сообщаете исходный каталог, и команда вызывает компилятор для вашего источника (см. пункт 8 раздела установки), а имя команды
ac
, откройте каталог
hello_world
в терминале и введите
ac ./
Теперь скопируйте файл
app.apk
на свой телефон и установить его.