Gradle beyond Android. Or going crazy with build automation

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.

F456ed67b75e58e533d11b301f5f62b5?s=128

Vitaliy Zasadnyy

October 10, 2015
Tweet

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. At GetSocial we make SDK to add social features to

    your app/game
  4. GetSocial SDK is available on three major platforms

  5. #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
  6. #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
  7. #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
  8. #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
  9. #devfestnl Available options Ant? No, just kidding :)

  10. #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
  11. #devfestnl Available options Grade looks like a dream comparing to

    Bash and Ant or Maven
  12. #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
  13. #devfestnl So what we're going to do?

  14. –Me If command line interface is available, we can automate

    We are going to create our own Unity Gradle plugin!
  15. #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
  16. #devfestnl Gradle Unity build > $UNITY_HOME/Unity -quit -batchmode -executeMethod GradleBuildHelper.PerformBuild

    COMMAND LINE There is full control on build process from C#
  17. #devfestnl Looks like we have a plan

  18. Gradle Unity Build Iteration 1. Time to rock

  19. Bunch of Gradle tasks we had at the end of

    iteration
  20. #devfestnl Iteration 1. Result Automated • Build • Unit /

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

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

    of the underlying Groovy language • Visible only in declaration scope
  23. #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.
  24. #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
  25. #devfestnl Local variables Extra properties vs. part of scope for

    calculations local accessibility part of project/task/… DSL configuration globally available
  26. #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
  27. #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
  28. #devfestnl Task dependencies • dependsOn do not preserve defined order

    • but you can order with mustRunAfter task cleanAll(dependsOn: [‘cleanAndroid', 'cleanRelease']) build.gradle
  29. #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
  30. #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
  31. #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
  32. Gradle Unity Build Iteration 2. We can do better

  33. #devfestnl Iteration 1. Problems • Big scripts hard to maintain

    • Not DRY enough • No separation of concerns
  34. This iteration is only about refactoring, set of tasks will

    stay the same
  35. Build script was separated to 6 files + few Groovy

    utility classes
  36. #devfestnl Split into several files apply from: 'gradle/ci.gradle' build.gradle task

    updateVersionInsideUnityProject() { ... } task switchBranchAndroid(type: Exec) { ... } ci.gradle
  37. #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
  38. #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
  39. #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
  40. Gradle Unity Build Iteration 3. In progress

  41. #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
  42. Defined Unity Gradle plugin DSL

  43. #devfestnl class UnityPlugin implements Plugin<Project> {
 void apply(Project project) {


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

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

    void apply(Project project) {
 project.extensions
 .create('unity', UnityPluginExtension, project)
 } UnityPlugin.groovy
  46. Takeaways

  47. #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
  48. Thank you! Questions? Vitaliy Zasadnyy @zasadnyy Presentation will be available

    at: v.zasadnyy.com/slides/