Wednesday, October 16, 2013

Android Studio + Gradle + Android Annotations

I've been trying to migrate to Android Studio and Gradle for a little while now and I think I finally figured it out.

So far these are the key points you need to know.

  • You don't need to really configure Android Studio to do packaging or code generation 
    • this is a small but significant difference when moving from Eclipse.  Android Studio fully uses the Gradle build system so tweaking options in it will either have no effect or screw things up.  
  • Android Studio is really focused on editing code not building applications (that's where Gradle comes in).  
    • I haven't deviated a whole lot from their default structure - I'm pretty certain you can anticipate "issues" if you convert a project or try to deviate from the convention.
    • The project structure in Android Studio is similar to Maven, although it can be overridden in your gradle file.


I was pretty new coming into Gradle and watching this video helped quite a bit: http://youtu.be/LCJAgPkpmR0 - it's the Goolge I/O 2013 New Android Build System talk.

To get up and running very quickly all you have to do is create a new project. In the same directory as your source directory create two directories :compileLibs and libs.  AndroidAnnotations has a code generation library called androidannotations-2.7.1.jar and their api (similarly) named androidannotations-api-2.7.1.jar.  The api library goes into the libs directory and the non-api lib goes into compile libs.

Once you have that setup all you have to do is drop this Gradle file in and you're off and running:
buildscript {
    repositories {
        mavenLocal()
        maven { url 'http://repo1.maven.org/maven2'}
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:0.5.+'
    }
}

apply plugin: 'android'

repositories {
    mavenCentral()
    maven {
        url 'https://oss.sonatype.org/content/repositories/snapshots/'
    }
}

configurations {
    compile
    androidannotations.extendsFrom(compile)
}

dependencies {
    compile fileTree(dir: 'libs', include: '*.jar')
    androidannotations fileTree(dir: 'compileLibs', include: '*.jar')
}

android {
    compileSdkVersion 17
    buildToolsVersion "17.0.0"
}

/*
over riding the android annotations output directory:
https://www.flexlabs.org/2013/05/support-android-annotations-in-gradle-projects
 */
def annotationDirs = file('src/main/aa_gen')

task annotationsDir {
    outputs.dir annotationDirs

    doFirst {
        if (!annotationDirs.isDirectory()) {
            println 'Creating: ' + annotationDirs
            annotationDirs.mkdirs()
        }
    }
}

tasks.clean.dependsOn tasks.cleanAnnotationsDir

afterEvaluate { project ->
    android.applicationVariants.each { variant ->
        variant.javaCompile.dependsOn annotationsDir
        variant.javaCompile.options.compilerArgs += [
                '-classpath', configurations.compile.asPath,
                '-processorpath', configurations.androidannotations.asPath,
                '-processor', 'com.googlecode.androidannotations.AndroidAnnotationProcessor',
                '-AandroidManifestFile=' + variant.processResources.manifestFile,
                '-s', annotationDirs
        ]
    }
}

Once I executed a gradle assemble command I did have to right click on the aa_gen folder and say "Mark Directory as Sources Root"

I think that's all I had to do in the end.  You should be able to be up and running in minutes (instead of weeks like me).

Happy Coding!

-Aaron


Friday, September 20, 2013

A clever command

Problem:
I have a bunch of log files in a directory on my SDCard on my Android device.  I want to pull them off the devices but you can't use ADB to pull multiple files - so this is a command to do that:

adb shell ls /some/dir | awk '{print "/some/dir"$0}' | tr '\r' ' ' | xargs -n1 adb pull

ok break that down: here is what's going on:

adb shell ls /some/dir - this outputs the files in the path but just the file name
| awk '{ print "/some/dir"$0   - this changes the file names to full path names
| tr '\r' ' ' - this formats the text so that xargs can understand the command correctly
xargs -n1 adb pull - executes the adb pull command with the absolute path name