Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Gradle beyond Android. Or going crazy with buil...

Gradle beyond Android. Or going crazy with build automation

Nowadays almost all Android projects are built with Gradle but do you know that Gradle is not only for Android? You can go pretty crazy with it's possibilities.

During the talk, Vitaliy will share his experience with adopting Gradle to manage complex GetSocial SDK build process with Android, iOS and Unity 3D subprojects.

As a bonus, he'll run quick walk through Gradle plugin creation process and tell how you can share it with the world.

Vitaliy Zasadnyy

October 10, 2015
Tweet

More Decks by Vitaliy Zasadnyy

Other Decks in Programming

Transcript

  1. Gradle beyond Android Or going crazy with build automation Vitaliy

    Zasadnyy Head of Mobile @ GetSocial Founder @ GDG Lviv
  2. #devfestnl Gradle is a first class build automation citizen on

    Android This presentation is about Gradle out of the scope of Android
  3. #devfestnl GetSocial SDK architecture Android SDK iOS SDK iOS Bridge

    Android Bridge C# API Unity SDK Java Objective C C# Public interfaces are exposed on: Android - Java, iOS - ObjectiveC, Unity - C# Unity SDK forwards calls to native SDKs via thin bridge layer
  4. #devfestnl Tasks to automate Build test apps Run Unit Tests

    Run Integration Tests Build Android SDK Build iOS SDK Build Unity SDK Generate Docs Deploy to Hokeyapp
  5. #devfestnl Prehistory of build automation at GetSocial • Android: Gradle

    + Eclipse • iOS: Xcode shell build scripts • Unity: bash scripts When I joined GetSocial automation was set up properly on Android and iOS On Unity - it was written long time ago => outdated and not working Main problem: 3 platforms - 3 different approaches to automation
  6. #devfestnl Requirements for new build pipeline • Unified • Crossplatform

    • Concise, clear and pragmatic • Powerful Unified: one tool for all platforms Crossplatform: work on Windows and OSX No way for XML or similar Powerful: it should be easy to extend automation logic
  7. #devfestnl Available options Bash pros: applicable to all our platforms;

    with Cygwin runs on Windows; pragmatic but not object oriented; powerful enough Bash cons: on Windows kind of magic, no
  8. #devfestnl Decisions made, let's start the journey • Android: out

    of the box • iOS: easy, openbackery gradle-xcodePlugin • Unity: no plugins On Unity there were no plugins, no code samples, even no questions on Stackoverflow
  9. –Me If command line interface is available, we can automate

    We are going to create our own Unity Gradle plugin!
  10. #devfestnl Gradle Unity build > $UNITY_HOME/Unity -quit -batchmode -executeMethod GradleBuildHelper.PerformBuild

    COMMAND LINE Unity expose very simple command line tool for automation. Main feature: invoke any public static method on C# side
  11. #devfestnl Iteration 1. Result Automated • Build • Unit /

    Integration tests • Beta Distribution build.grade 600+ lines
  12. #devfestnl Local variables def releaseDir = "$buildDir/release" task copyReadme(type: Copy)

    {
 from "$rootDir/README.md"
 into releaseDir
 } build.gradle Declare and use variables
  13. #devfestnl Local variables def releaseDir = "$buildDir/release" build.gradle • Feature

    of the underlying Groovy language • Visible only in declaration scope
  14. #devfestnl Extra properties project.ext {
 unityProjectDir = "$rootDir/unity-src"
 sdkVersion =

    "4.0.0"
 targetPlatform = "Android"
 } build.gradle Gradle objects like projects, tasks, and source sets can hold extra user- defined properties.
  15. #devfestnl Extra properties project.ext {
 unityProjectDir = "$rootDir/unity-src"
 } build.gradle

    • Part of Gradle domain model • Available for projects, tasks, source sets, etc. • Accessible via the owning object's ext property
  16. #devfestnl Local variables Extra properties vs. part of scope for

    calculations local accessibility part of project/task/… DSL configuration globally available
  17. #devfestnl Tasks task helloWorld << {
 println "Hello world!"
 }

    build.gradle > gradle helloWorld
 Hello world! COMMAND LINE Tasks create a public API of the build script, available via command line Task is a part of the work to do in automation process
  18. #devfestnl Task dependencies build.gradle task cleanAll(dependsOn: [‘cleanAndroid', 'cleanRelease']) build.gradle task

    buildJars(dependsOn: 'android:assemble') {
 ext.getSocialEnvironment = 'master'
 } build.gradle Gradle do not preserve defined order Tasks can be chained
  19. #devfestnl Task dependencies • dependsOn do not preserve defined order

    • but you can order with mustRunAfter task cleanAll(dependsOn: [‘cleanAndroid', 'cleanRelease']) build.gradle
  20. #devfestnl dependsOnOrdered static dependsOnOrdered(Task task, Task... others) {
 task.dependsOn(others)
 for

    (int i = 0; i < others.size() - 1; i++) {
 others[i + 1].mustRunAfter(others[i])
 }
 } build.gradle task cleanAll {
 dependsOnOrdered(cleanAll, *[cleanAndroid, cleanRelease,])
 } build.gradle Any missing behaviour can be easily implemented with Groovy
  21. #devfestnl task buildUnity(type: Exec) << {
 commandLine "$unityExecutableDir/Unity",
 "-platform=$targetPlatform",
 "-sdkVersion=$sdkVersion",


    '-quit'
 } Extending existing tasks build.gradle • Other: JavaCompile, Jar, Javadoc, Delete… • You can create Tasks to extend
  22. #devfestnl extensions.buildTypes = new BuildTypes(project)
 buildTypes {
 ciDevelop 'ci', getSocialEnvironment:

    'testing'
 ciMaster 'ci', getSocialEnvironment: 'master'
 } Build Types build.gradle • Custom implementation of Build Types • Switch to native in near future
  23. #devfestnl Iteration 1. Problems • Big scripts hard to maintain

    • Not DRY enough • No separation of concerns
  24. #devfestnl Split into several files apply from: 'gradle/ci.gradle' build.gradle task

    updateVersionInsideUnityProject() { ... } task switchBranchAndroid(type: Exec) { ... } ci.gradle
  25. #devfestnl Split into several files • Splited into 6 *.gradle

    files • Separated logic • DRAWBACK: can’t share common tasks apply from: 'gradle/ci.gradle' build.gradle
  26. #devfestnl package im.getsocial.unity
 
 class GetSocialUtils {
 static createDirIfNotExist(dirPath) {

    ... }
 } Move common tasks to Groovy GetSocialUtils.groovy • Sources location: buildSrc/src/main/groovy/ • Groovy syntax 95% Java compatible Use Groovy, it has tons of syntax sugar, code will be much more readable
  27. #devfestnl Move common tasks to Groovy import im.getsocial.unity
 
 createDirIfNotExist(“$rootDir/build”)

    build.gradle package im.getsocial.unity
 
 class GetSocialUtils {
 static createDirIfNotExist(dirPath) { ... }
 } GetSocialUtils.groovy
  28. #devfestnl Requirements • Add support for Build Variants • Expose

    simple configuration DSL • Encapsulate logic in plugins DSL should be as sexy as Android Gradle Plugin DSL Besides having debug/release builds we also need internal/public test apps Build logic should be encapsulated inside
  29. #devfestnl class UnityPlugin implements Plugin<Project> {
 void apply(Project project) {


    ...
 }
 } Define plugins UnityPlugin.groovy apply plugin: UnityPlugin build.grade
  30. #devfestnl class UnityPluginExtension {
 String logOutput = 'build/build-log.txt'
 } Add

    extensions UnityPlugin.groovy void apply(Project project) {
 project.extensions
 .create('unity', UnityPluginExtension)
 } UnityPlugin.groovy
  31. #devfestnl Add extensions unity {
 logOutput = 'demo-app-build-log.txt'
 } build.grade

    void apply(Project project) {
 project.extensions
 .create('unity', UnityPluginExtension, project)
 } UnityPlugin.groovy
  32. #devfestnl Takeaways • Automate all the things with Gradle •

    Keep it DRY with Groovy / Java util classes • Separate concerns with plugins • UnityGradle plugin will be open sourced