Пишем, собираем и запускаем HelloWorld для Android в блокноте

от автора

Когда я начал изучать Android, захотелось полностью написать и скомпилировать Android-приложение вручную — без использования IDE. Однако эта задача оказалась непростой и заняла у меня довольно много времени. Но как оказалось — такой подход принёс большую пользу и прояснил многие тонкости, которые скрывают IDE.

По-сути эта статья является переводом и переработкой статьи Building Android programs on the command line под современные на данный момент JDK (7) и Android SDK (API level 19). Кроме того, я многое упростил и добавил кое-что от себя.

Используя только блокнот, мы напишем совсем маленькое учебное Android-приложение. А затем скомпилируем его, соберём и запустим на устройстве — и всё через командную строку. Заинтересовало? Тогда прошу.

Вступление

Я был поражён, насколько сложным и запутанным является шаблонное приложение в android studio. Оно просто нагромождено ресурсами. И в меньшей степени — кодом и скриптами. Хотя всё что оно должно делать — это выводить на экран HelloWorld! Кроме того, в книгах и руководствах, которые я просмотрел, объясняется, как с помощью диалоговых окон создать IDEA-шный или эклипсовый HelloWorld — и от него уже идёт дальнейшее повествование. А что происходит «под капотом» — остаётся только гадать.

Долгие поиски были почти безрезультатны — на русском языке статей по данной теме я не нашёл, а на английском — была устаревшая информация и кое-что пришлось дорабатывать напильником, гуляя по stackowerflow и документации. Когда я разобрался, то решил восполнить пробел — вдруг кому-то пригодится? Собственно, так и появилась эта статья.

Мы создадим свой шаблонный проект, который идеально использовать для обучения. Там не будет ничего лишнего, только всё самое необходимое. А потом детально разберём, как его собрать и запустить на вашем Android-устройстве. В конце статьи будет ссылка на скачивание архива с итоговым проектом — если возникнут какие-то вопросы — можете свериться с ним.

Таким образом, вы будете на 100% знать и понимать состав вашего проекта и процесс его сборки. Хотя этот тестовый проект предназначен для обучения, при небольшой доработке его можно будет использовать как прочный фундамент для ваших реальных проектов.

Подготовка

Для начала у вас должен быть установлен JDK 7 и android SDK. Последний кстати нужно чуточку настроить после установки.

Главное требование перед прочтением этой статьи — кроме установленного софта вы должны уже уметь запускать на вашем девайсе тот Helloworld, который поставляется вместе с Eclipse или Android Studio. Т.е. у вас должен быть настроен драйвер usb, включена отладка по usb на вашем девайсе и т.д… Или же создан и настроен эмулятор. Это совсем элементарные вещи, и их рассмотрение выходит за рамки данной статьи — в сети достаточно информации. Кстати прочитать пару глав из книг тоже будет не лишним — хотя бы понимать, как устроен манифест, ресурсы, да и вообще основы языка Java. А в этой статье я опишу то, о чём книги молчат.

Написание проекта

Для начала, создайте некоторую папку, где будет ваш проект. Назовём её mytestapp. В ней создайте ещё 4 папки — bin,obj,res и src.

Создайте пустой текстовый файл и измените его имя на AndroidManifest.xml. Если вы начинающий пользователь Windows, вам нужно включить показ расширений, иначе файл будет по-прежнему текстовым.

Добавьте в него следующее:

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.testapp">     <uses-sdk android:targetSdkVersion="19" />      <application android:label="TestApp">         <activity android:name=".MainActivity">             <intent-filter>                 <action android:name="android.intent.action.MAIN" />             </intent-filter>         </activity>     </application> </manifest>

Тут всё просто. Мы намерены сделать приложение с именем TestApp, которое при старте запускает класс MainActivity. Осталось только написать этот небольшой класс — и приложение готово. Если нужно — отредактируйте в теге uses-sdk свойство android:targetSdkVersion — поставьте ту версию, которая у вас.

Далее — создадим простейший ресурс — строку Hello test app. Вообще-то мы могли обойтись и без ресурса, вставив эту строку прямо в Java код. Но некоторые шаги сборки работают с ресурсами, и чтобы увидеть интересные моменты — мы всё-таки поработаем с ними.

Давайте создадим в папке res папку values. Все ресурсы следует разбивать по папкам. Далее — в ней создадим пустой файл strings.xml. а в нём напишем

<resources>     <string name="hello">Hello test app!</string> </resources>

Вот и все ресурсы, нам необходимые. Просто, не так ли? Далее создадим внутри src папку com, в ней папку example, потом ещё ниже по иерархии папку testapp — а там уже наш класс MainActivity.java. Добавим туда код

package com.example.testapp;  import android.app.Activity; import android.os.Bundle; import android.widget.TextView;  public class MainActivity extends Activity {    @Override   public void onCreate(Bundle savedInstanceState) {     super.onCreate(savedInstanceState);      TextView textView = new TextView(this);     textView.setText(getString(R.string.hello));     setContentView(textView);   } }

Структура каталогов должна получится такая

│   AndroidManifest.xml ├───bin ├───obj ├───res │   └───values │           strings.xml │ └───src     └───com         └───example             └───testapp                     MainActivity.java 

И это собственно всё, что нам было нужно для простейшего проекта. Для сравнения —

HelloWorld от android studio

│   .gitignore │   AndroidStudioHWProject.iml │   build.gradle │   gradlew │   gradlew.bat │   local.properties │   settings.gradle │ ├───.gradle │   └───1.8 │       └───taskArtifacts │               cache.properties │               cache.properties.lock │               fileHashes.bin │               fileSnapshots.bin │               outputFileStates.bin │               taskArtifacts.bin │ ├───.idea │   │   .name │   │   compiler.xml │   │   encodings.xml │   │   gradle.xml │   │   misc.xml │   │   modules.xml │   │   vcs.xml │   │   workspace.xml │   │ │   ├───copyright │   │       profiles_settings.xml │   │ │   ├───libraries │   │       ComAndroidSupportAppcompatV71901_aar.xml │   │       support_v4_19_0_1.xml │   │ │   └───scopes │           scope_settings.xml │ ├───AndroidStudioHW │   │   .gitignore │   │   AndroidStudioHW.iml │   │   build.gradle │   │ │   ├───build │   └───src │       └───main │           │   AndroidManifest.xml │           │ │           ├───java │           │   └───com │           │       └───example │           │           └───androidstudiohw │           │                   MainActivity.java │           │ │           └───res │               ├───drawable-hdpi │               │       ic_launcher.png │               │ │               ├───drawable-mdpi │               │       ic_launcher.png │               │ │               ├───drawable-xhdpi │               │       ic_launcher.png │               │ │               ├───drawable-xxhdpi │               │       ic_launcher.png │               │ │               ├───layout │               │       activity_main.xml │               │       fragment_main.xml │               │ │               ├───menu │               │       main.xml │               │ │               ├───values │               │       dimens.xml │               │       strings.xml │               │       styles.xml │               │ │               └───values-w820dp │                       dimens.xml │ └───gradle     └───wrapper             gradle-wrapper.jar             gradle-wrapper.properties 

Собственно, автоматизация через gradle, работа с git и IDE — вещи очень важные, однако на этапе изучения Android мне бы очень хотелось от них абстрагироваться.

Сборка

Теперь же подходим к самому важному и сложному этапу. Мы будем много работать с командной строкой, поэтому рекомендую вам все команды, данные здесь, записывать в один файл и назвать его comp.bat. В конце файла после команд можете добавить pause, чтобы был виден результат и ошибки — если таковые возникнут.

Подготовка путей

Первое, что мы сделаем для удобства и краткости — создадим специальные переменные, в которых будем хранить пути. Для начала — определим наши основные директории. Вам нужно заменить пути к JDK и Android SDK на те, которые у вас.

set JAVA_HOME=C:\prog\sdk\jdk\1.7 set ANDROID_HOME=C:\prog\sdk\android-studio\sdk set DEV_HOME=%CD% 

Далее — пути непосредственно к программам. Я рекомендую вам просмотреть каталоги ваших SDK и убедится в том, что всё на месте. Также подкорректировать версии, которые присутствуют в путях.

set AAPT_PATH=%ANDROID_HOME%/build-tools/19.0.1/aapt.exe set DX_PATH=%ANDROID_HOME%/build-tools/19.0.1/dx.bat set ANDROID_JAR=%ANDROID_HOME%/platforms/android-19/android.jar set ADB=%ANDROID_HOME%/platform-tools/adb.exe 

Между прочим, в более старых версиях утилита aapt находилась в platform-tools — и я не исключаю что она и\или другие могут слинять куда-нибудь ещё. Так что будьте внимательны. Если вы всё правильно сверите сейчас — то остальная часть статьи должна пройти гладко.

И ещё — в пару переменных забьём наши пакеты и классы. Если заходите их сменить — вам не придётся бегать по коду — все настройки вначале.

set PACKAGE_PATH=com/example/testapp set PACKAGE=com.example.testapp set MAIN_CLASS=MainActivity 

Подготовка к компиляции

А теперь самое интересное. Помните, как классические Java-программы компилируются и запускаются в 2 строчки? Здесь мы используем тот же самый javac, однако кроме него нам предстоит использовать ещё много утилит.

Для начала спрошу — а вы никогда не задумывались, как работает загадочный класс R? Собственно меня он сперва смутил из-за его сверхъестественных возможностей. Как на этапе компиляции можно через поля класса обращаться к XML-файлам в других каталогах? Я предположил, что тут орудует прекомпилятор — так оно и оказалось.

Собственно, есть специальная утилита AAPT — она проходится по каталогам ваших ресурсов и создаёт тот самый R.java. Оказывается, всё очень даже просто — это просто класс, в составе которого другие статические вложенные классы с целочисленными константами. И всё! Он выглядит примерно так

R.java

/* AUTO-GENERATED FILE.  DO NOT MODIFY.  *  * This class was automatically generated by the  * aapt tool from the resource data it found.  It  * should not be modified by hand.  */  package com.example.testapp;  public final class R {     public static final class attr {     }     public static final class string {         public static final int hello=0x7f020000;     } } 

Теперь давайте создадим его у вас. Для этого используем следующие команды:

call %AAPT_PATH% package -f -m -S %DEV_HOME%/res -J %DEV_HOME%/src -M %DEV_HOME%/AndroidManifest.xml -I %ANDROID_JAR%

После его выполнения в каталоге src должен появится тот самый файл R.java. Проверьте.

Теперь в нашем проекте нет никакой магии и он полностью синтаксически корректен для обычного Java-компилятора. Давайте скомпилируем его.

call %JAVA_HOME%/bin/javac -d %DEV_HOME%/obj -cp %ANDROID_JAR% -sourcepath %DEV_HOME%/src %DEV_HOME%/src/%PACKAGE_PATH%/*.java

После выполнения в папке obj должны находится пакеты с нашими классами в виде байт-кода (*.class). Но вот ведь незадача — виртуальная машина андроида с ним не совместима! Но так было задумано и на это есть причины. А мы используем конвертер, который делает из class-файлов dex-файл, понятный для нашего зелёного R2D2.

call %DX_PATH% --dex --output=%DEV_HOME%/bin/classes.dex %DEV_HOME%/obj

Убедитесь в том, что в папке bin находится наш classes.dex. Теперь осталось только упаковать его вместе с ресурсами в APK-файл. Сделаем это:

call %AAPT_PATH% package -v -f -M %DEV_HOME%/AndroidManifest.xml -S %DEV_HOME%/res -I %ANDROID_JAR% -F %DEV_HOME%/bin/AndroidTest.unsigned.apk %DEV_HOME%/bin

В папке bin теперь должен появится AndroidTest.unsigned.apk. И мы назвали его не просто так! У него нет цифровой подписи. Андроид запрещает устанавливать и запускать приложения без подписи. Но создать её не так-то трудно, как может показаться на первый взгляд

call %JAVA_HOME%/bin/keytool -genkey -validity 10000 -dname "CN=AndroidDebug, O=Android, C=US" -keystore %DEV_HOME%/AndroidTest.keystore -storepass android -keypass android -alias androiddebugkey -keyalg RSA -v -keysize 2048 call %JAVA_HOME%/bin/jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore %DEV_HOME%/AndroidTest.keystore -storepass android -keypass android -signedjar %DEV_HOME%/bin/AndroidTest.signed.apk %DEV_HOME%/bin/AndroidTest.unsigned.apk androiddebugkey

Собственно, эти строчки запускают 2 Java-утилиты, которые не имеют никакого отношения к Android SDK — но они необходимы. Первая создаёт файл AndroidTest.keystore (проверьте его наличие), а вторая — этот файл соединяет с AndroidTest.unsigned.apk. Получается файл AndroidTest.signed.apk. Вот такой дикий крафт файлов. Но однажды создав bat-скрипт запускайте его — и он будет делать всё это в автоматическом режиме.

У вас, скорее всего, будет предупреждение "Warning: No -tsa or -tsacert is provided and this jar…", но не обращайте внимание.

Запуск

Теперь, когда мы наконец собрали наш apk-файл — можем его запустить. Подключите по usb ваше устройство, или же запустите эмулятор. А затем выполните

call %ADB% uninstall %PACKAGE% call %ADB% install %DEV_HOME%/bin/AndroidTest.signed.apk call %ADB% shell am start -n %PACKAGE%/%PACKAGE%.%MAIN_CLASS%

Собственно, первая строчка удаляет программку, если она уже там есть. Для повторных запусков пригодится. Вторая — устанавливает APK на ваш девайс или эмулятор. Третья же — запускает. Не пугайтесь обилия ‘%’ в коде — это всего лишь подстановка переменных — хороший подход.

Если всё прошло удачно, вы увидите что-то вроде этого:

Заключение

После сборки всех файлов дерево каталогов должно быть примерно таким.

│   AndroidManifest.xml │   AndroidTest.keystore │   comp.bat │ ├───bin │       AndroidTest.signed.apk │       AndroidTest.unsigned.apk │       classes.dex │ ├───obj │   └───com │       └───example │           └───testapp │                   MainActivity.class │                   R$attr.class │                   R$string.class │                   R.class │ ├───res │   └───values │           strings.xml │ └───src     └───com         └───example             └───testapp                     MainActivity.java                     R.java 

Теперь вы можете наглядно увидеть и понять, как происходит сборка андроид-приложения на более низком уровне. Когда будете использовать IDE — если сборка вдруг пойдёт не так (а такое часто бывает) — сможете вырулить ситуацию как надо.

Выкладываю архив проекта (Нажимайте Файл-Скачать). Обратите внимание, что я добавил туда ещё один маленький скрипт — clear.bat. Он удаляет все созданные при сборке файлы. И поставил его запуск на начало comp.bat. Также добавил комментарии после Rem — по шагам.

Таким образом, скрипт производит полную очистку и пересборку проекта, включая подпись, а также удаление его на устройстве, установку и запуск.

ссылка на оригинал статьи http://habrahabr.ru/post/210584/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *