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

Geoff Matrangola- Migrating Your Apps to the New Gradle Build Process

Geoff Matrangola- Migrating Your Apps to the New Gradle Build Process

4867789d19ac436c6e5a4e79b956c4b0?s=128

NewCircle Training

December 17, 2013
Tweet

Transcript

  1. Migrating Your Apps to the new Gradle Build Process From

    Ant to Gradle AnDevCon SF 2013
  2. About Geoff @triglm

  3. Getting to Know You • How many… • Apps? •

    Developers on your team? • Using Eclipse? • Using Ant? • Using Android Studio? • Using Gradle? • Continuous Integration?
  4. History • Android started off with Eclipse and Ant integrated

    into the Android Development Kit • Eclipse is the IDE and Ant the command-line/automated build tool. • Google I/O April 2013 Xavier Ducrohet Announced deprecating Eclipse and Ant in favor of IntellaJ and Gradle
 http://www.youtube.com/watch?v=LCJAgPkpmR0
 http://tools.android.com/tech-docs/new-build-system/ user-guide
  5. Gradle Overview • Build System • Declarative • Customization -

    Plugins, Domain Specific Language (DSL) • APIs and IDE Integration • Free/ Open Source • Convention over configuration • Maven and Ant Integration • Based on Groovy http://www.gradle.org
  6. Simple Gradle File for Java • Convention • Code:src/main/java •

    Tests:src/test/java • Resources src/main/resources • Output goes to build/… build.gradle apply plugin: ’java’
  7. Simple Gradle File for Java build.gradle apply plugin: ’application’ mainClassName

    = "com.matrangola.hello.Hello"
  8. Using the Android Gradle Plugin build.gradle buildscript { repositories {

    mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.6.+' } } apply plugin: 'android' ! repositories { mavenCentral() } ! android { compileSdkVersion 19 buildToolsVersion "19.0.0" ! defaultConfig { minSdkVersion 7 targetSdkVersion 19 } } ! dependencies { compile 'com.android.support:appcompat-v7:+' }
  9. Android/Gradle Directory Structure

  10. Android/Ant Directory Structure

  11. The Easy Way - Export/ Change Configuration In Eclipse/ADT •

    Back up your source! • Update in SDK Manager • Help->Check for Updates • File->Export->
 Android->
 Generate Gradle build files <demo>
  12. The Easy Way part 2 In Android Studio • Import

    Project… • IF you get a “Resolve Error” update… • ./gradle/wrapper/gradle-wrapper.properties • distributionUrl=http\://services.gradle.org/ distributions/gradle-1.8-all.zip • build.gradle:
 classpath ‘com.android.tools.build:gradle:0.6.+’
 compileSdkVersion 19
 buildToolsVersion "19.0.0" • run ./gradlew tasks <demo>
  13. The Easy Way Part 3 build.gradle buildscript { repositories {

    mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.6.+' } } apply plugin: 'android' ! dependencies { compile fileTree(dir: 'libs', include: '*.jar') compile project(':YambaClientLib') compile project(':YambaContract') } ! android { compileSdkVersion 18 buildToolsVersion "17.0.0" ! sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] } ! instrumentTest.setRoot('tests') } } <demo>
  14. Exported File: Section by Section buildscript { repositories { mavenCentral()

    } dependencies { classpath 'com.android.tools.build:gradle:0.6.+' } } apply plugin: 'android' • buildscript - this is the configuration for Gradle at build time. • repositories - repositories where the Gradle plugins are found • dependencies - plugins etc. for Gradle - not available for the compiler, but for the thing that runs the compiler • apply plugin - use the android plugin found in the dependency artifact
  15. Exported File: Section by Section dependencies { compile fileTree(dir: 'libs',

    include: '*.jar') compile project(':YambaClientLib') compile project(':YambaContract') } • dependencies - this module’s dependencies. Can be other modules (projects) .jar files or maven artifacts. • compile fileTree - include all the jar files in the libs directory (just like and and eclipse) • compile project - use the Android Library listed. Similar to the “is library” checkbox on the Android config page in ADT and using android update lib-project in Ant.
  16. Exported File: Section by Section android { compileSdkVersion 18 buildToolsVersion

    “17.0.0" … } • android - configure the parameters for the android build. No need for the java plugin. • compileSdkVersion - required. Similar to the —target option in the old android update project tool or selecting the target in the Eclipse IDE. Can be an int or string (i.e. 15 or “Google Inc.:Google APIs:15”) • buildToolsVersion - Specify the version of the android built tools. This use the android command or toolbar button in Android Studio to bring up the SDK manager.
  17. Exported File: Section by Section android { … sourceSets {

    main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] resources.srcDirs = ['src'] aidl.srcDirs = ['src'] renderscript.srcDirs = ['src'] res.srcDirs = ['res'] assets.srcDirs = ['assets'] } ! instrumentTest.setRoot('tests') } ! } • android - Continued • sourceSets - configure the project structure when you want something different than the default • main - primary source tree - default “flavor”, more on next slide • instrumentTest.setRoot - traditional android unit tests.
  18. Move to full Gradle adoption build.gradle buildscript { repositories {

    mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.6.+' } } apply plugin: 'android' ! dependencies { compile fileTree(dir: 'libs', include: '*.jar') compile project(':YambaClientLib') compile project(':YambaContract') } ! android { compileSdkVersion 18 buildToolsVersion "17.0.0" } <demo> Get rid of the main section that defined the directory layout that matched the old build tools.
  19. Make the move to The Full Gradle • mkdir src/main/java

    • mv src/com (or whatever) to src/main/java/ • mkdir src/main/aidl • mv src/main/java/**/*.aidl /src/main/aidl • mv assets src/main/assets • mv res src/main • mv AndroidManifest.xml src/main • … <demo>
  20. Main Anchor Tasks • assemble = compile -> jar ->

    apk • assembleDebug • assembleRelease • check = assemble and run tests • connectedCheck • deviceCheck • build = assemble + check • clean = delete build contents of build dir
  21. Gradle Tricks • Flavors • Compute Version Number automatically •

    Native Code • Icon Convert on the fly (vector to png)
  22. App Flavor Trick • Build multiple versions of your app

    • Change package name • Different assets, resources, even Java code • Build common stuff once • AndroidManifest is built by merging flavors
  23. App Flavors • Same Type as defaultConfig (set the same

    fields) • Combined with Build Type (i.e. Debug Release) • Matching src Directories android { … productFlavors { pro { packageName "com.example.pro" } ! demo { packageName "com.example.demo" } } …
  24. src/free/assets/license.properties src/pro/assets/license.properties App Flavors Directory structure matches that of the

    productFlavors in parallel with src/main cost=Expensive … cost=Free …
  25. demo pro debug assembleDemoDebug assembleProDebug assembleDebug release assembleDemoRelease assembleProRelease assembleRelease

    assembleDemo assemblePro assemble App Flavors $> ./gradlew assembleDemoDebug $> ./gradlew assembleDemoRelease $> ./gradlew assembleProDebug $> ./gradlew assembleProRelease $> ./gradlew assembleDemo $> ./gradlew assemblePro $> ./gradlew assembleDebug $> ./gradlew assembleRelease $> ./gradlew assemble
  26. Compute Version Number Trick • Use the Revision number in

    you Version Control System • Put in in the versionCode Property in Gradle • Gradle builds the androidManifest file
  27. Automatic Version Number • android section • defaultConfig - setup

    what will go into the AndroidManifest.xml • versionCode - android:VersionCode & android:versionName android { defaultConfig { versionCode svnInfo.rev.toInteger() versionName "4.1.0 Rev: ${svnInfo.rev}" } … } …
  28. Automatic Version Number • outside android section • define a

    new task svnInfo • use groovy fu to call your VCS and redirect stdout to a byte stream that you will convert to a string • take the stdout string and use regex to extract the rev or other • return using the ext capability task svnInfo { new ByteArrayOutputStream().withStream { os -> def result = exec { executable = 'svn' args = ['info'] standardOutput = os } def outputAsString = os.toString() def matchRev = outputAsString =~ /Revision: (\d+)/ ext.rev = matchRev[0][1] println "Latest Changed Revision #: ${ext.rev}" } }
  29. Build Native Code Trick • No Support built in •

    Copying files • Building Jar • Adding Jar to .apk
  30. Prepare JNI • Move Java assets, etc.. • mkdir src/main/java

    • mv src/com (or whatever) to src/main/java/ • mkdir src/main/aidl • mv src/main/java/**/*.aidl /src/main/aidl • mv assets src/main/assets • mv res src/main • mv AndroidManifest.xml src/main • … • Move JNI • mv jni src/main/jni • Install NDK • Set NDK_HOME environment variable <demo>
  31. Update build.gradle <demo> // Tasks for configuring the Native projects

    task copyNdkSrc(type:Copy) { // copy so that the libs and obj directory // will be built in the build directory description "copy from src/main/jni to $buildDir/jni" from "src/main/jni" into "$buildDir/jni" include '**/*' } ! task ndkBuild(dependsOn: ['copyNdkSrc'], type:Exec) { description "Build the Native JNI library" outputs.dir "$buildDir/obj" inputs.dir "$buildDir/jni" environment NDK_PROJECT_PATH:'build' commandLine "${System.env.NDK_HOME}/ndk-build" args 'V=1' } Copy the source before building, otherwise it will pollute the src directory.
  32. Update build.gradle <demo> ndkBuild.doLast { // libs is used by

    the Android build later file("$buildDir/libs").renameTo("$buildDir/ndk-libs") } ! task nativeLibsToJar(type: Zip, dependsOn: ndkBuild) { description 'create a jar archive of the native libs' buildDir.mkdir() destinationDir new File(file(buildDir), "native-libs") baseName 'native-libs' extension 'jar' from fileTree(dir: "$buildDir/ndk-libs", include: '**/*.so') into 'lib/' } Move the native libs out of the generic libs directory.
  33. Update build.gradle <demo> gradle.projectsEvaluated { preBuild.dependsOn(nativeLibsToJar) } Set up the

    dependency so it builds automatically.
  34. Automatic Icon Conversion Trick • Start with the assets directly

    from your graphic artist • Integrate updates more quickly • Automatically generate icons based on each pixel density bin • res/drawable-hdpi • res/drawable-mdpi • res/drawable-xhdpi • res/drawable-xxhdpi • Not Android Specific
  35. Automatic Icon Conversion • outside android section • inputs and

    outputs keep track of changes and only run if necessary • doLast means “run in build phase” • convert is a groovy function that I made up task convert { FileTree inputFiles = fileTree(dir:'icons/widget', include: '**/*.svg') inputs.files inputFiles outputs.files findOutFiles(res, inputFiles, [‘xxhdpi', 'xhdpi', 'hdpi', 'mdpi', 'ldpi'], '') doLast { def res = ‘src/main/res’ convert(res, 'icons/widget', '', ‘xxhdpi’, '3') convert(res, 'icons/widget', '', ‘xhdpi’, '2') convert(res, 'icons/widget', '', ‘hdpi’, '1.5') convert(res, 'icons/widget', '', ‘mdpi’, '1') convert(res, 'icons/widget', '', ‘ldpi’, '.75') } }
  36. Automatic Icon Conversion • outside android section • groovy function

    with params and return value • looks for output files based on the resource directory structure List<File> findOutFiles(String res, FileTree inFiles, List<String> profiles, String suffix) { List<File> outFiles = [] inFiles.each {File file -> profiles.each { String resProfile -> String outPath = "$res/drawable-$resProfile/$ {file.name.substring(0, file.name.indexOf('.'))}$ {suffix}.png" outFiles += new File(outPath) } } return outFiles }
  37. Automatic Icon Conversion • groovy function outside any section •

    parameters etc. • fileTree gathers a list of files (.svg files in this case) • runs the rsvg-convert program for each file found in the file Tree def convert(String res, String dir, String suffix, String resProfile, String zoom) { FileTree files = fileTree(dir:dir, include: '**/*.svg') files.each { File file -> String outPath = “$res/drawable-$resProfile/“ + “${file.name.substring(0, file.name.indexOf('.'))}$ {suffix}.png" exec { executable = "rsvg-convert" args = ["--zoom=$zoom", '-a', '--format=png', '-o', outPath, file.absolutePath] } } }
  38. Automatic Icon Conversion • Update the libs dependency to include

    native jar. dependencies { compile fileTree(dir: "$buildDir/native-libs", include: '*.jar') }
  39. Thanks/References • Gradle android plugin announcement: http:// www.youtube.com/watch?v=LCJAgPkpmR0 • Gradle

    Android Plugin docs http://tools.android.com/ tech-docs/new-build-system/user-guide • Yamba demo app originated by Marco Gargenta and the Marakana/New Circle Team https://github.com/ twitter-university/yamba • Gradle http://gradle.org
  40. Thank You Please Leave Feedback! Especially if you liked it!