Pull to refresh

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

Reading time 10 min
Views 48K
Обычно у разработчика есть свой любимый инструмент, которым ему пользоваться удобнее, чем другими. Однако бывает так, что платформа заставляет разработчиков брать в руки инструмент, который не так удобен, как ему хотелось бы, или просто чем-то не устраивает. Так получилось, что традиционно приложения под 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 разрабатывается параллельно с новым редактором, идущим на замену 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. Как это можно сделать, я опишу в следующей части статьи.
Tags:
Hubs:
+11
Comments 4
Comments Comments 4

Articles