...

четверг, 19 ноября 2015 г.

Gradle: 5 полезностей для разработчика

Привет, Хабр! Настало время, когда можно сказать, что «new build system» Gradle является стандартом отрасли Android-разработки. Инструмент сделан настолько просто и удобно, что большинство разработчиков не испытает трудностей, даже не зная, как он устроен, и какие дополнительные возможности в нём есть — возникающие проблемы легко решаются с помощью 5 минут на StackOverflow, путем копирования «магического кода» в конфигурационные файлы. Возможно, в том числе из-за этого не все разработчики изучают Gradle детально и не знают о многих его полезных возможностях, которые существенно облегчают жизнь.


Речь пойдет о:

  1. Увеличении быстродействия
  2. Расширении BuildConfig
  3. Использовании переменных
  4. Выключении Crashlytics
  5. Уменьшении количества конфигураций ресурсов

1. Увеличиваем быстродействие


Время сборки напрямую влияет на скорость разработки. Тесты показывают, что каждая из версий, начиная с Gradle 2.0, становилась медленнее предыдущей. Однако затем разработчики исправились и хорошенько поработали над быстродействием в Gradle 2.4.

1. Поэтому первым делом следует убедиться, что вы используете актуальную версию Gradle 2.4+

        sm:~ sm$ gradle -v
        Gradle 2.4

2. Затем, удостоверившись, что вы пытаетесь ускорить свою рабочую машину, а не сервер CI, включить Gradle демон — это даст значительный прирост в скорости сборки.
Строки конфигурации стоит добавлять в файл ./%project%/gradle.properties, если вы хотите распространить конфигурацию на все проекты, то необходимо конфигурировать файл, лежащий в домашней папке вашего пользователя
~/.gradle/gradle.properties

        org.gradle.daemon=true # включаем демон

Почему на CI-сервере не стоит включать Gradle Daemon

Gradle демон позволяет делать сборки более быстро, но при Gradle переиспользует runtime предыдущей сборки, по этой причине крайне важные требования для CI не выполняются. А именно стабильность и предсказуемость, чистота runtime и полная изолируемость от предыдущих сборок.

3. После чего, проверив что модули вашего проекта не используют друг-друга как зависимости, тем самым создавая перекрёстные ссылки, можно смело включать режим параллельного выполнения, что также ускорит скорость сборки до ~30%.

        org.gradle.parallel=true # включаем режим параллельного выполнения

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

        org.gradle.configureondemand=true

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

2. Расширяем BuildConfig


Как известно, файл конфигурации сборки (build.gradle) предоставляет возможность определить Product Flavors и Build Types, что даёт нам массу вариантов для разделения сборок по назначению. Например, “Сборка с тестовым сервером”, “Сборка с боевым сервером”, ”Сборка с логированием” и другие. Использование их для расширения BuildConfig (который генерируется каждый раз при сборке) даёт нам потрясающую гибкость. Например, удобное переключение между back-end-сервером, с которым работает наше приложение; включение/выключение определённого функционала – например, логи.

В build.gradle:

android {
    ...
    buildTypes {
        debug {
            buildConfigField "String", "SERVER_PREFIX", "\"test.\""
        }
        release {
            buildConfigField "String", "SERVER_PREFIX", "\"\""
        }
    }    
}

В java коде:

// …
public final class NetworkConstants {
    // …

    public static final String SERVER_ADDRESS = "http://" + BuildConfig.SERVER_PREFIX + "server.com/";

    // …
}

Разница между Product Flavors и Build Types
Product Flavor — это механизм, который позволяет нам определять различные варианты сборки приложения. У одного проекта могут быть различные варианты сборки(flavors), при выборе варианта(flavor) будет изменяться генерируемое приложение.
Build Type — конфигурация того, как приложение будет упаковано. У каждого приложения по умолчанию есть два Build Type – debug и release. Можно сделать и другие. Идеологически Build Type не предназначен для изменения приложения, только упаковки. Собственно это и является основным различием, которое выливается в различные наборы параметров, которые предоставляются для настройки Product Flavors и Build Types.

3. Используем переменные


Время не стоит на месте, а значит инструменты, библиотеки и Android имеют свойство обновляться. И если приложение развивается, то приходится открывать build.gradle и менять как минимум compileSdkVersion, buildToolsVersion, версии Android Support Library и Google Play Services. А если у нас в проекте используется много модулей или различные части библиотеки Google Play Services, это ведет к большому количеству мест изменений, и можно легко потерять время из-за опечатки в каком-то из файлов. Кроме того, возможно использование различных библиотек и инструментов в разных проектах, что плохо и может стать причиной проблем. Избежать подобной ситуации помогут gradle-переменные.

В самый верхний build.gradle добавляем

// …
ext.compileSdkProjectVersion= 23
ext.buildToolsProjectVersion= '23.0.1'
ext.supportLibraryVersion = '23.1.0'
ext.googlePlayVersion = '8.3.01’

В остальных ./%module%/build.gradle их можно будет использовать, выглядеть это будет примерно так:

android {
    compileSdkVersion compileSdkProjectVersion
    buildToolsVersion buildToolsProjectVersion
    //…
}

dependencies {
    compile "com.android.support:appcompat-v7:$supportLibraryVersion"
    compile "com.google.android.gms:play-services-base:$googlePlayVersion"
    compile "com.google.android.gms:play-services-maps:$googlePlayVersion"
    compile "com.google.android.gms:play-services-location:$googlePlayVersion"
}

4. Выключаем Crashlytics


В большинстве случаев собирать аварийные завершения необходимо только в Release-сборках, которые мы выпускаем для пользователей/тестирования. Debug сборки разработчик использует для себя, и аварийные завершения будут видны ему в лог-файле, значит, дабы не засорять список реальных аварийных завершений у пользователей, необходимо выключить Crashlytics для Debug-сборок.
Задачу можно выполнить банальной проверкой типа сборки:
// App.java
// …
public final class App extends Application {
// ...
    @Override
    public void onCreate() {
        // …
        if ( !BuildConfig.DEBUG ) {
            Fabric.with(this, new Crashlytics());
        }
        // …
    }
// …
}

Но это не самое лучшее решение, т.к. плагин Fabric Gradle всё равно будет тратить время на генерацию и встраивание в ресурсы приложения уникального id сборки, чтобы Crashlytics back-end затем понял, какая сборка прислала данные. Поэтому применим более удобное решение, которое позволит ускорить время сборки debug-версии приложения.

В build.gradle:

android {
    //…

    buildTypes {
        debug {
          ext.enableCrashlytics = false
          // …
        }
    }

    // …
}

После этого debug-сборки не будут получать id, и процесс сборки ускорится, но следует учитывать, что если разработчик попытается инициализировать в такой сборке Crashlytics, то приложение упадёт с выводом:

com.crashlytics.android.core.CrashlyticsMissingDependencyException:
This app relies on Crashlytics. Please sign up for access at http://ift.tt/1DC2RSD`

Т.е. обязательно оставьте проверку на тип сборки и используйте Crashlytics только для Release сборок или воспользуйтесь решением, приведённым в документации к Crashlytics на сайте Fabric:

// App.java
// …
public final class App extends Application {
    // ...

    @Override
    public void onCreate() {
        // …
        //Создаём Crashlytics,выключенный для debug сборок
        Crashlytics crashlyticsKit = new Crashlytics.Builder()
            .core(new CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
            .build()

        // Инициализируем Fabric с выключенным crashlytics.
        Fabric.with(this, crashlyticsKit);
        // …
    }

    // …
}

5. Уменьшаем количество конфигураций ресурсов


В разрабатываемых нами приложениях мы часто используем сторонние библиотеки, например, Android Support Library, Google Play Services и другие. Многие из библиотек поставляются с различными внутренними ресурсами, которые в наших приложениях абсолютно не нужны. Например, Google Play Services поставляется с переводом на языки, которые ваше приложение не поддерживает. Вероятно вы также не захотите поддерживать mdpi или tvdpi-разрешение в своём приложении.
Благодаря Android Gradle Plugin мы можем установить яscala и разрешения, которые используются в приложении, остальные будут исключены, что позволит уменьшить вес.
// build.gradle 

android {
    defaultConfig {
        resConfigs "en", "ru"
        resConfigs "nodpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
    }
}

При необходимости можно подойти более радикально и начать использовать multi-APK, тем более когда появился новый удобный механизм Splits.

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


Этим рубрику полезных советов по Gradle закончим, их ещё много, но, на мой взгляд, вышеперечисленные являются наиболее интересными. Наверняка у вас есть и свои, интересно будет увидеть их в комментариях :) На этом всё, спасибо за внимание!

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

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 http://ift.tt/jcXqJW.

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

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