Gradle build command android

Building Android applications with Gradle — Tutorial

This tutorial describes the usage of the Gradle build system for building Android applications. It includes the information how to configure build flavors.

1. Gradle for building Android applications

1.1. Using Gradle for Android apps

By default, Android projects are handled by the Gradle build system. If you create a new project in Android studio, the Gradle build scripts are automatically created. Android studio provides the Gradle runtime, hence no additional installation is required.

If you press the run button in Android Studio, it triggers the corresponding Gradle task and starts the application.

You can also run Gradle via the command line. To avoid unnecessary local installation, Gradle provides a wrapper script which allows you to run Gradle without any local installation.

You find the available versions of the Android Gradle plug-in under the following URL: https://jcenter.bintray.com/com/android/tools/build/gradle/

1.2. Conversion process from source code to Android application

The Java source files are converted to Java class files by the Java compiler. The Android SDK contains a tool called dx which converts Java class files into a .dex (Dalvik Executable) file. All class files of the application are placed in this .dex file. During this conversion process redundant information in the class files are optimized in the .dex file. For example, if the same String is found in different class files, the .dex file contains only one reference of this String .

These .dex files are therefore much smaller in size than the corresponding class files.

The .dex file and other resources, e.g., the images and XML files, are packed into an .apk (Android Package) file. The program aapt (Android Asset Packaging Tool) performs this step.

The resulting .apk file contains all necessary data to run the Android application and can be deployed to an Android device via the adb tool.

As of Android 5.0 the Android RunTime (ART) is used as runtime for all Android applications. ART uses a combination of Ahead Of Time and _Just In Time _ compilation. During the installation of an application on an Android device, the application code is translated into machine code.

The dex2oat tool takes the .dex file created by the Android tool chain and compiles that into an Executable and Linkable Format (ELF file). This file contains the dex code, compiled native code and meta-data. Keeping the .dex code allows that existing tools still work.

1.3. Using Gradle on the command line

The Gradle build system is designed to support complex scenarios in creating Android applications:

Multi-distribution: the same application must be customized for several clients or companies

Multi-apk: supporting the creation of multiple apk for different device types while reusing parts of the code

You can start your Gradle build via the command line. Here is an overview of the important Android Gradle tasks:

Table 1. Android Gradle build targets

build project, runs both the assemble and check task

./gradlew clean build

build project complete from scratch

./gradlew clean build

build project complete from scratch

Run the instrumentation tests

To see all available tasks, use the gradlew wrapper command.

This command creates in the build folder the output of the Gradle build. By default, the Gradle build creates two .apk files in the build/outputs/apk folder.

To build and start your unit tests on the JVM use the following command.

To build and start your instrumented tests on your Android device use the following command.

1.4. Removing unused resources and Java classes via resource shrinking

The Gradle build system for Android supports resource shrinking at build time. This automatically removes resources that are unused from the packaged application. In addition to that, this also removes unnecessary resources from libraries you are depending on. This can hugely reduce the size of your application.

To enable resource shrinking, update your build file similar to the following snippet.

1.5. Defining dependencies and keeping the version external

A good practice is to define the version of your library dependencies outside the dependencies closure for better maintenance.

Command Description
If you put the ext closure into the root build file, you can access its properties for example with ‘$rootProject.ext.junitVersion’.

2. Building different flavors of your Android applications

2.1. Build types and build flavors

Android uses by default two build types: debug and release. For these build types you can create different flavors in you Gradle build.

The Gradle build system is also able to manage different flavors of an application. A product flavor defines a customized version of the application. This allows that some parts of the codebase or the resources can be different for variations of the app.

For instance, you can define different build variants for certain device categories, like phone or tablet. Another use case might be a paid or a free version of your app. Or you want to use different resources or classes during a test run.

2.2. Defining product flavors in your Gradle build file

You can use the productFlavors closure of you app/build.gradle file to define different variants of your product.

The whole build.gradle file might look like the following:

After defining these flavors you can select them in the Build Variants view in Android Studio.

2.3. Providing different resources for the flavors

In order to define a different behavior for a certain flavor, you need to create suitable folders for the defined flavors under app/src/.

Flavor specific resources override the main resources. For example, if you provide a different application icon in a flavor the Android build system picks up the flavor specific one.

2.4. Providing different source sets for the product flavors

The directories in the src/ folder are called source sets. Every product flavor can define its own source set.

Code files are not replaced as resources, they are combined. For example, you cannot have a com.example.MainActivity activity in your app/main/java/ folder and a different implementation in another flavor. If you try this, you receive an error message about duplicate class definitions.

You can still provide different implementations by avoiding the creation of the class in your main source folder and instead create a class in each flavor.

3. Optional exercise: Using different product flavors for apps

In this exercise you create an Android application with two different project flavors, called prod and mock.

The mock version defines different resources than the prod version. In this first sample the strings.xml file of the main folder/project is overridden. Which variant is build is defined via the Build Variants view.

3.1. Creating a new Android application

Create a new Project with the Empty Activity template and the top level package com.vogella.android.gradlebuildflavors .

Define two additional product flavors in the app/build.gradle file called «prod» and «mock».

Create the desired folder structure for prod and mock flavors.

Copy the strings.xml from the main folder to the appropriate folder of the flavor.

Change the hello_world string of the strings.xml to Mock World! and Prod World! accordingly.

3.2. Validate

Select mockDebug as Build Variant in the Build Variants view of Android Studio and run your app.

If you start you application you should see the string from the mock flavor. Select now you prod flavor and start it, you should see the other string.

3.3. Build via Gradle command line

Use the ./gradlew build command to build all your product flavors.

4. Providing different classes for testing and production

4.1. Prepare your application for testing with Gradle flavors

Create a class ShareIntentBuilder which starts an activity via the “share intent” via a static method with the following code.

4.2. Implement different MainActivity versions for your flavors

Allow the activity which triggers this intent to be replaced in your “mock” flavor. If in a flavor “mock” is selected, start a second activity in your application which displays the send data. If the flavor «prod» is selected send the shared intent.

Источник

Шпаргалка по Gradle

Как мне кажется, большинство людей начинают разбираться с gradle только тогда, когда в проекте что-то надо добавить или что-то внезапно ломается — и после решения проблемы «нажитый непосильным трудом» опыт благополучно забывается. Причём многие примеры в интернете похожи на ускоспециализированные заклинания, не добавляющие понимания происходящего:

Я не собираюсь подробно описывать, для чего нужна каждая строчка выше — это частные детали реализации андроид-плагина. Есть кое-что более ценное — понимание того, как всё организовано. Информация раскидана по различным сайтам/официальной документации/исходникам градла и плагинов к нему — в общем, это чуть более универсальное знание, которое не хочется забывать.

Дальнейший текст можно рассматривать как шпаргалку для тех, кто только осваивает gradle или уже забыл.

Полезные ссылки

Консоль

Android studio/IDEA старательно прячет команды gradle от разработчика, а ещё при изменении build.gradle файликов начинает тупить или перезагружать проект.

В таких случаях вызывать gradle из консоли оказывается намного проще и быстрее. Враппер для gradle обычно идёт вместе с проектом и прекрасно работает в linux/macos/windows, разве что в последнем надо вызывать bat-файлик вместо враппера.

Вызов задач

пишет доступные задачи.

Можно вывести задачи отдельного подпроекта, а ещё с опцией —all будут выведены все задачи, включая второстепенные.

Можно вызвать любую задачу, при этом будут вызваны все задачи, от которых она зависит.

Если лень писать название целиком, можно выкинуть маленькие буковки:

Если градл не сможет однозначно угадать, какую именно задачу имели ввиду, то выведет список подходящих вариантов.

Логгинг

Количество выводимой в консоль информации при запуске задачи сильно зависит от уровня логгинга.
Кроме дефолтного есть -q, -w, -i, -d , ну или —quiet, —warn, —info, —debug по возрастанию количества информации. На сложных проектах вывод с -d может занимать больше мегабайта, а поэтому его лучше сразу сохранять в файл и там уже смотреть поиском по ключевым словам:

Если где-то кидается исключение, для stacktrace опция -s .

Можно и самому писать в лог:

логгер является имплементацией SLF4J.

Groovy

Происходящее в build.gradle файликах — просто код на groovy.

Groovy как язык программирования почему-то не очень популярен, хотя, как мне кажется, он сам по себе достоин хотя бы небольшого изучения. Язык появился на свет ещё в 2003 году и потихоньку развивался. Интересные особенности:

  • Практически любой java код является валидным кодом на groovy. Это очень помогает интуитивно писать работающий код.
  • Одновременно вместе со статической, в груви поддерживается динамическая типизация, вместо String a = «a» можно смело писать def a = «a» или даже def map = [‘one’:1, ‘two’:2, ‘list’ = [1,false]]
  • Есть замыкания, для которых можно динамически определить контекст исполнения. Те самые блоки android <. >принимают замыкания и потом исполняют их для какого-то объекта.
  • Есть интерполяция строк «$a, $» , multiline-строки «»»yep, $«»» , а обычные java-строки обрамляются одинарными кавычками: ‘text’
  • Есть подобие extension-методов. В стандартной коллекции языка уже есть методы типа any, every, each, findAll. Лично мне названия методов кажутся непривычными, но главное что они есть.
  • Вкусный синтаксический сахар, код становится намного короче и проще. Можно не писать скобки вокруг аргументов функции, для объявления списков и хеш-табличек приятный синтаксис: [a,b,c], Gradle build command android

В общем, почему языки типа Python/Javascript взлетели, а Groovy нет — для меня загадка. Для своего времени, когда в java даже лямбд не было, а альтернативы типа kotlin/scala только-только появлялись или ещё не существовали, Groovy должен был выглядеть реально интересным языком.

Именно гибкость синтаксиса groovy и динамическая типизация позволила в gradle создавать лаконичные DSL.

Сейчас в официальной документации Gradle примеры продублированы на Kotlin, и вроде как планируется переходить на него, но код уже не выглядит таким простым и становится больше похожим на обычный код:

Впрочем, переименование в Kradle пока не планируется.

Стадии сборки

Их делят на инициализацию, конфигурацию и выполнение.

Идея состоит в том, что gradle собирает ациклический граф зависимостей и вызывает только необходимый минимум их них. Если я правильно понял, стадия инициализации происходит в тот момент, когда исполняется код из build.gradle.

Возможно, это неочевидно, но вышеуказанное будет тормозить инициализацию. Чтобы не заниматься копированием файлов при каждой инициализации, нужно в задаче использоваль блок doLast <. >или doFirst <. >— тогда код завернётся в замыкание и его позовут в момент выполнения задачи.

В старых примерах вместо doLast можно встретить оператор , но от него потом отказались из-за неочевидности поведения.

tasks.all

Что забавно, с помощью doLast и doFirst можно навешивать какие-то действия на любые задачи:

IDE подсказывает, что у tasks есть метод whenTaskAdded(Closure . ) , но метод all(Closure . ) работает намного интереснее — замыкание вызывается для всех существующих задач, а так же на новых задачах при их добавлении.

Создадим задачу, которая распечатает зависимости всех задач:

Если tasks.all<> вызвать во время выполнения (в блоке doLast ), то мы увидим все задачи и зависимости.
Если сделать то же самое без doLast (т.е., во время инициализации), то у распечатанных задач может не хватать зависимостей, так как они ещё не были добавлены.

Ах да, зависимости! Если другая задача должна зависеть от результатов выполнения нашей, то стоит добавить зависимость:

inputs, outputs и инкрементальная сборка

Обычная задача будет вызываться каждый раз. Если указать, что задача на основе файла А генерирует файл Б, то gradle будет пропускать задачу, если эти файлы не изменились. Причём gradle проверяет не дату изменения файла, а именно его содержимое.

Аналогично можно указать папки, а так же какие-то значения: inputs.property(name, value) .

task description

При вызове ./gradlew tasks —all стандартные задачи имеют красивое описание и как-то сгруппированы. Для своих задач это добавляется очень просто:

task.enabled

можно «выключить» задачу — тогда её зависимости будут всё равно вызваны, а она сама — нет.

несколько проектов (модулей)

В основном проекте можно расположить ещё несколько модулей. Например, такое используется в андроид проектах — в рутовом проекте почти ничего нет, в подпроекте включается android плагин. Если захочется добавить новый модуль — можно добавить ещё один, и там, например, тоже подключить android плагин, но использовать другие настройки для него.

Ещё пример: при публикации проекта с помощью jitpack в рутовом проекте описывается, с какими настройками публиковать дочерний модуль, который про факт публикации может даже не подозревать.

Дочерние модули указываются в settings.gradle:

Подробнее про зависимости между проектами можно почитать здесь

buildSrc

Если кода в build.gradle много или он дублируется, его можно вынести в отдельный модуль. Нужна папка с магическим именем buildSrc , в которой можно расположить код на groovy или java. (ну, вернее, в buildSrc/src/main/java/com/smth/ код, тесты можно добавить в buildSrc/src/test ). Если хочется что-то ещё, например, написать свою задачу на scala или использовать какие-то зависимости, то прямо в buildSrc надо создать build.gradle и в нём указать нужные зависимости/включить плагины.

К сожалению, с проектом в buildSrc IDE может тупить c подсказками, там придётся писать импорты и классы/задачи оттуда в обычный build.gradle тоже придётся импортировать. Написать import com.smth.Taskname — не сложно, просто надо это помнить и не ломать голову, почему задача из buildSrc не найдена).

По этой причине удобно сначала написать что-то работающее прямо в build.gradle , и только потом переносить код в buildSrc .

Свой тип задачи

Задача наследуется от DefaultTask , в которой есть много-много полей, методов и прочего. Код AbstractTask, от которой унаследована DefaultTask.

  • вместо ручного добавления inputs и outputs можно использовать поля и аннотации к ним: @Input, @OutputFile и т.п.
  • метод, который будут запускать при выполнении задачи: @TaskAction .
  • удобные методы типа copy всё ещё можно вызвать, но придётся их явно вызывать для проекта: project.copy

Когда для нашей задачи кто-то в build.gradle пишет

у задачи вызывается метод configure(Closure) .

Я не уверен, что это правильных подход, но если у задачи есть несколько полей, взаимное состояние которых сложно контролировать геттерами-сеттерами, то кажется вполне удобным переопределить метод следующим образом:

Причём даже если написать

то метод configure всё равно будет вызван.

Свой плагин

Подобно задаче, можно написать свой плагин, который будет что-то настраивать или создавать задачи. Например, происходящее в android <. >— полностью заслуга тёмной магии андроид плагина, который вдобавок создаёт целую кучу задач типа app:assembleDevelopDebug на все возможные сочетания flavor/build type/dimenstion. Ничего сложного в написании своего плагина нет, для лучшего понимания можно посмотреть код других плагинов.

Есть ещё третья ступенька — можно код расположить не в buildSrc , а сделать его отдельным проектом. Потом с помощью https://jitpack.io или ещё чего-то опубликовать плагин и подключать его аналогично остальным.

The end

В примерах выше могут быть опечатки и неточности. Пишите в личку или отмечайте с ctrl+enter — исправлю. Конкретные примеры лучше брать из документации, а на эту статью смотреть как на списочек того «как можно делать».

Источник

Читайте также:  Андроид студио адаптер это
Оцените статью