...

воскресенье, 5 января 2014 г.

Разработка под Android в NetBeans IDE без плагинов. Часть 1

Обычно у разработчика есть свой любимый инструмент, которым ему пользоваться удобнее, чем другими. Однако бывает так, что платформа заставляет разработчиков брать в руки инструмент, который не так удобен, как ему хотелось бы, или просто чем-то не устраивает. Так получилось, что традиционно приложения под Android пишут при помощи Eclipse, поскольку Google приняли решение о том, что будут разрабатывать официальный плагин, ADT, именно для этого редактора. В результате тем разработчикам, которые им не пользовались, волей-неволей пришлось его освоить.

К счастью, Google также предоставляют систему сборки, которая работает независимо от имеющегося в наличии IDE. А это означает, что можно настроить любой редактор для работы с приложениями Android. Лично я предпочитаю писать код на Java в NetBeans IDE и хочу поведать о том, как его можно настроить для этого. Есть такие плагины, как nbandroid, но разрабатывается он нерегулярно, энтузиастами, так что есть смысл воспользоваться гибкостью NetBeans и задействовать официальную систему сборки напрямую из редактора.


Создание нового проекта




При создании нового проекта, к сожалению, придётся сделать больше действий, чем можно было бы сделать в Eclipse, но это нужно сделать всего лишь один раз. Создание проекта делается в три шага:

  1. Создание файлов для сборки из командной строки;

  2. Создание проекта в IDE;

  3. Добавление дополнительных команд (по вкусу).




Создание файлов для сборки



Прежде всего, необходимо создать новый проект через командную строку. Я буду исходить из предположения, что в PATH уже затесалась папка <Android-SDK>/tools. Проект создаётся следующей командой:

android create project -n <имя проекта> -t android-<уровень API> -p <путь к проекту> -k <пакет программы> -a <название основной активности>


На всякий случай поясню, что уровень API — это тот самый, с помощью которого мы будем компилировать проект. То есть если проект в целом рассчитан на уровень API 10, но есть некоторые возможности, которые используются только на аппаратах с уровнем 15 и выше, то нужно именно 15 и выставить. В AndroidManifest.xml, кстати, эта 15 не засветится, там будет только 10 как минимально необходимый уровень API.


Предположим, что наш проект создаётся для Android 4.0.3 (это уровень 15) и называется KillerApp. Тогда нужно будет ввести следующее:


android create project -n KillerApp -t android-15 -p KillerApp -k com.damageinc.killerapp -a MainActivity


После этой команды в папке проекта завелись все нужные нам файлы: конфигурационные файлы и, самое главное, файл сборки. На этом работа с командной строкой закончена, и мы больше её не увидим. Теперь осталось поколдовать в IDE.


Создание проекта в IDE




  1. На экране создания нового проекта в NetBeans понадобится пункт Java Free-Form Project, с помощью которого мы растолкуем IDE, где брать файл сборки.

    1. New Project



  2. Дальше нужно выбрать папку проекта. NetBeans сам найдет файл сборки и сообразит, как называется проект, так что после выбора папки можно спокойно идти на следующий экран.

    2. Name and Location



  3. А вот теперь надо правильно прописать задания сборки, чтобы IDE знал, что запускать, когда мы заходим собрать проект. Сборка в системе осуществляется заданием debug. Это немного странно выглядит, но причина такого названия очень простая: это задание создаёт сборку для отладки, подписанную соответствующим сертификатом. Соответственно, есть задание release, до которого мы ещё доберёмся. Запуск проекта в нашем случае означает сборку и установку, что означает выполнение задания install после сборки. Там ещё приписано задание launch, которого в стандартной системе нет, но мы его сделаем и сами. Очистка — это, вполне ожидаемо, clean, а тестировать в Android нужно через отдельный, тестовый проект, поэтому то, что находится в том поле, можно смело стирать.

    3. Build and Run Actions



  4. На следующем экране нужно добавить папку gen к папкам исходников, потому что именно в этой папке будет находится файл R.java.

    4. Source Package Folders



  5. Теперь настраиваем подсказки по коду. Прежде всего, важно снять флажок разделения папок с исходниками, иначе IDE будет думать, что файл R не должен упоминаться в коде нашей программы, поскольку лежит в отдельной папке. Также нужно добавить правильную платформу Android в список библиотек, в нашем случае это <Android-SDK>/platforms/android-15/android.jar.

    5. Java Sources Classpath



  6. И, наконец, последний шаг, добавляем папку bin/classes, чтобы IDE знал, где искать скомпилированный код. В принципе, этот шаг не обязателен, и на него можно смело наплевать. Но для полноты картины я сделаю и его, чтобы NetBeans показывал, какие файлы были недавно изменены и ещё не скомпилированы.

    6. Project Output




Добавление дополнительных команд



На самом деле, после последнего шага можно больше ничего не делать. Проект создан и уже нормально собирается. Но можно пойти дальше и наделать много удобств. В папку проекта стоит положить файл custom_rules.xml , а в нём записать
необходимые нам задания ant


<project name="CustomRules">
<target name="release-and-save" depends="release">
<xpath
input="AndroidManifest.xml"
expression="/manifest/@android:versionName"
output="manifest.versionName"
default="test"/>
<xpath
input="AndroidManifest.xml"
expression="/manifest/@android:versionCode"
output="manifest.versionCode"
default="test"/>
<copy
file="${out.final.file}"
tofile="releases/${ant.project.name}-release${manifest.versionCode}-${manifest.versionName}.apk"
overwrite="true"/>
<copy
file="${obfuscate.absolute.dir}/mapping.txt"
tofile="releases/mapping-release${manifest.versionCode}.txt"
overwrite="true"/>
</target>

<target name="rebuild-resources" depends="-set-debug-mode, -build-setup, -code-gen" />

<target name="-find-main-activity">
<xpath
input="AndroidManifest.xml"
expression="/manifest/@package"
output="project.app.package"
default="test"/>
<xpath
input="AndroidManifest.xml"
expression="/manifest/application/activity[intent-filter/category/@android:name = 'android.intent.category.LAUNCHER'][1]/@android:name"
output="project.app.mainactivity"
default="test"/>
<if>
<condition>
<matches pattern="\..+|[^\.].*\..*[^\.]" string="${project.app.mainactivity}"/>
</condition>
<then>
<property name="project.app.mainactivity.qualified" value="${project.app.mainactivity}"/>
</then>
<else>
<property name="project.app.mainactivity.qualified" value=".${project.app.mainactivity}"/>
</else>
</if>
<property name="project.app.launcharg" value="-a android.intent.action.MAIN -n ${project.app.package}/${project.app.mainactivity.qualified}"/>
</target>

<target name="launch" depends="-find-main-activity">
<exec executable="adb">
<arg line="shell am start"/>
<arg line="${project.app.launcharg}"/>
</exec>
</target>
</project>





Эти три задания нам позволяют делать кое-какие весьма полезные вещи. rebuild-resources позволяет сгенерировать файл R (который в Eclipse, кстати, нередко куда-то исчезает или не обновляется вовремя). launch даст нам возможность запускать приложения, а release-and-save позаботится о том, чтобы при сборке финальной версии она сохранилась в отдельной папке под соответствующим именем вместе с картой методов ProGuard. Ещё я люблю добавлять такие строчки, чтобы после сборки проигрывалось уведомление:

<target name="-post-build">
<sound>
<success source="C:\Windows\Media\Windows Notify.wav"/>
</sound>
</target>




Разумеется, этот конкретный вариант звука годится только для Windows, для других ОС стоит выбрать другой файл. Теперь осталось добавить эти задания в контекстное меню в NetBeans. В свойствах проекта на вкладке Build and Run мы уже заранее доработали пункт Run Project заданием launch в конце. В пользовательские элементы контекстного меню я добавил остальные только что сделанные задания:

Build and Run


Теперь в конекстном меню проекта весь букет необходимых нам команд. Можно запустить эмулятор или подключить смартфон, запустить Run и смотреть, как всё собирается и само запускается. Осталось сделать последние штрихи и включить обфускацию при сборке финальной версии, раскомментировав строчку в файле project.properties :


proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt


Также в ant.properties стоит прописать строчки для подписи финальных сборок:


key.store = <путь к файлу ключей>

key.alias = <название ключа>


Вот теперь у нас проект готов к работе.


Как работает система сборки в Android




На самом деле, системы сборки в Android на данный момент сейчас уже две: одна основана на ant, а другая — на Gradle. В данном конкретном случае мы пользуемся системой ant. Система с Gradle разрабатывается параллельно с новым IDE, идущим на замену Eclipse — Android Studio. Эта система сборки, думаю, пригодится для отдельной статьи.

Возвращаясь к ant, в папке проекта лежат следующие файлы:



  • ant.properties

  • build.xml

  • local.properties

  • proguard-project.txt

  • project.properties




Самый важный файл здесь — это, разумеется, build.xml. На самом деле, это лишь маленький хвостик основной системы, и всё, что он делает — это загрузка свойства из файлов с расширением properties и вызов основной системы, располагающейся в самом SDK.

local.properties содержит всего лишь одно свойство: расположение папки с SDK. Этот файл нужно занести в список исключений системы контроля версий, потому что он содержит настройки, специфические для отдельной машины. Например, у меня под Windows этот файл содержит строчку


sdk.dir=C:\\Android-SDK


На самом деле, можно создать переменную окружения ANDROID_HOME с содержимым переменной из этого файла и благополучно отправить файл в мусорку. Главное, не забудьте после этого перезапустить NetBeans.


С ant.properties мы уже познакомились, там хранятся вспомогательные переменные вроде расположения хранилища ключей. Также есть файл project.properties. После действий, описанных в создании проекта, там есть только строчки об уровне API Android, для которого собирается проект, и о том, где искать файл конфигурации ProGuard. Когда мы будем добавлять в проект библиотеки, строчки о них окажутся там же.


Наконец, файл proguard-project.txt, который, как следует из названия, содержит указания ProGuard. Он изначально пуст, но это вовсе не значит, что ProGuard будет работать вхолостую, поскольку в папке SDK уже есть заранее записанная конфигурация (помните раскомментированную строчку о ProGuard?), а здесь мы можем её конкретизировать. Например, я лично люблю, помимо прочих, добавлять строчки


-renamesourcefileattribute MyProject

-keepattributes SourceFile,LineNumberTable


Они в дальнейшем помогают собирать отчёты об ошибках, поскольку теперь есть точные данные о том, какая строчка кода в проекте вызывает падение или исключение.


Также build.xml загружает файл custom_rules.xml, если он есть, в котором мы и добавили все необходимые нам задания. Стоит взглянуть на задания ещё раз.



<target name="rebuild-resources" depends="-set-debug-mode, -build-setup, -code-gen" />




Эти строчки взяты просто из системы сборки SDK. К сожалению, там они не вынесены в отдельное задание, поэтому пришлось делать это самостоятельно. Интереснее взглянуть на другие два задания:

<target name="release-and-save" depends="release">
<xpath
input="AndroidManifest.xml"
expression="/manifest/@android:versionName"
output="manifest.versionName"
default="test"/>
<xpath
input="AndroidManifest.xml"
expression="/manifest/@android:versionCode"
output="manifest.versionCode"
default="test"/>
<copy
file="${out.final.file}"
tofile="releases/${ant.project.name}-release${manifest.versionCode}-${manifest.versionName}.apk"
overwrite="true"/>
<copy
file="${obfuscate.absolute.dir}/mapping.txt"
tofile="releases/mapping-release${manifest.versionCode}.txt"
overwrite="true"/>
</target>




С помощью XPath здесь достаются параметры версии и дальше с их помощью генерируются имена файлов. В обычном ant поддержки XPath нет, так откуда же он тут взялся? В Android SDK Google добавили свои собственные инструменты для того, чтобы работать с приложениями было удобнее. Многие из их инструментов сводятся к запуску определённых файлов из SDK, но есть и те, которые облегчают написание файлов сборки, такие как xpath. Ещё одним полезным инструментом, например, является if, делающий именно то, что делает соответствующая конструкция в языках программирования: выполнение того или иного задания в зависимости от условия.

Второе задание тоже использует xpath, на этот раз задача немного сложнее:



<target name="-find-main-activity">
<xpath
input="AndroidManifest.xml"
expression="/manifest/@package"
output="project.app.package"
default="test"/>
<xpath
input="AndroidManifest.xml"
expression="/manifest/application/activity[intent-filter/category/@android:name = 'android.intent.category.LAUNCHER'][1]/@android:name"
output="project.app.mainactivity"
default="test"/>
<if>
<condition>
<matches pattern="\..+|[^\.].*\..*[^\.]" string="${project.app.mainactivity}"/>
</condition>
<then>
<property name="project.app.mainactivity.qualified" value="${project.app.mainactivity}"/>
</then>
<else>
<property name="project.app.mainactivity.qualified" value=".${project.app.mainactivity}"/>
</else>
</if>
<property name="project.app.launcharg" value="-a android.intent.action.MAIN -n ${project.app.package}/${project.app.mainactivity.qualified}"/>
</target>

<target name="launch" depends="-find-main-activity">
<exec executable="adb">
<arg line="shell am start"/>
<arg line="${project.app.launcharg}"/>
</exec>
</target>




Необходимо найти активность, которая определяет в своем фильтре намерений категорию android.intent.category.LAUNCHER — именно так в Android определяются активности, которые должны показываться в меню. Их может быть и несколько (хотя это бывает редко), поэтому задание берёт первую из них.

Есть и ещё одна загвоздка. Активности декларируются в AndroidManifest.xml либо записью с полным именем, либо только именем класса с точкой впереди, если активность лежит в главном пакете. По крайней мере, так говорит документация. Только вот проблема в том, что Eclipse и прочий инструментарий позволяет точку опускать и просто писать имя активности, когда она находится в главном пакете. Android-то такое попустительство терпит, а вот команда, запускающая приложения, уже нет. Приходится добавлять точку, когда её не хватает. Вот тут нам и поможет задание if, недавно мной упомянутое, и регулярные выражения.


Также было ещё совсем простое задание, которое воспроизводит звук. В нём был использован один из шести хуков, которые дёргаются из файла сборки в SDK:



  • -pre-build

  • -pre-compile

  • -post-compile

  • -post-package

  • -post-build

  • -pre-clean




Хуки отражают этапы, через которые проходит сборка программы: компиляция библиотек, генерирование кода (RenderScript, aidl, R, BuildConfig), компиляция проекта, упаковкой APK, подпись и zipalign. Соответственно, -pre-build вызывается прежде, чем начнутся все эти действия, -pre-compile непосредственно перед компиляцией самого проекта, -post-compile — между компиляцией и упаковкой, -post-build — после упаковки, но до подписи, и -post-build вызывается в самом конце. Ну а когда вызывается -pre-clean, думаю, понятно из названия.

Вместо заключения




Сегодня мы посмотрели самое важное: создание проекта. Собственно, уже после этого проект вполне рабочий, можно садиться и строчить код. Но нам нужно будет добавлять в проект библиотеки, отлаживать, а также создавать тесты. Все эти действия тоже отлично получаются в NetBeans. Как это можно сделать, я опишу в следующей части статьи.

This entry passed through the Full-Text RSS service — if this is your content and you're reading it on someone else's site, please read the FAQ at fivefilters.org/content-only/faq.php#publishers.


Комментариев нет:

Отправить комментарий