Android Annotations Processor Plugin

| Comments

The other day I explained how to use Android Annotations with Gradle on Android Studio. There was a lot of Groovy to write before starting to program. I discover the android-apt plugin for Gradle which reduces my last post to boilerplate code. The excilys team advices to use it for building android annotations with Gradle.

This plugin does not target android annotations specifically but it helps you to work with android and annotation processors and make life easier on Android Studio.

Starting a new android application with Gradle and android annotations is simple:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.7.+'
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.2'

    }
}
apply plugin: 'android'
apply plugin: 'android-apt'

repositories {
    mavenCentral()
}

configurations {
    apt
}


dependencies {
    compile 'com.android.support:appcompat-v7:+'
    compile 'org.androidannotations:androidannotations-api:3.0'
	
    apt 'org.androidannotations:androidannotations:3.0'
}

android {
    compileSdkVersion 19
    buildToolsVersion "19.0.1"

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 19
    }
    buildTypes {
        release {
            runProguard false
            proguardFile getDefaultProguardFile('proguard-android.txt')
        }
    }
    productFlavors {
        defaultFlavor {
            proguardFile 'proguard-rules.txt'
        }
    }
    signingConfigs {
        myConfig {
            storeFile file(project.property("MyProject.signing"))
            storePassword "xxxxxxxxx"
            keyAlias "yageek company"
            keyPassword "xxxxxxxxxx"
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.myConfig
        }
    }
}

apt {
    arguments {
        androidManifestFile variant.processResources.manifestFile
    }
}

Android Studio, Gradle and Android Annotations

| Comments

I switched for some days from iOS to Android to start a new project and refresh a little bit my knowledge about the Android toolchain.

I’m not a first hour user of Java and I have to admit that I do not follow all news about new Java tools or features. I discovered IntelliJ and Gradle only 8 months ago. This was a very good discover and makes me forget old and disapointing experiences with Ant, Eclipse/Netbeans and XML configuration. I really thought XML was a part of the language. The announcement of Android Studio at the last Google I/O sounded like a resurrection of some of old projects on my hard drive disk.

Another bad experience with Android was the lot of boilerplate Java you have to write anytime you code GUI stuffs. In French GNU/Linux magazine I discovered the amazing android annotated library android annotations which do a million more than just avoid you to call the findViewById method. After a lot of time reading the Gradle documentation and browsing Stack Overflow topics about this building tool, I succeed in having a working environment with Android Studio, Gradle and AndroidAnnotations on my laptop (OSX 10.9). I’ll try to share and explain my build.gradle in this post.

Pay attention to the version of Android Studio, Android SDK tools and Gradle you’re using !

Here I am using Android Studio v0.4.2, Android SDK tools 19.0.1 and Gradle 1.9. I notice some problems by using the Gradle version provided with Android Studio. I rather download Gradle somewhere on my hard drive disk and configure Android Studio to use it (Android Studio -> Preferences).

Let’s try some explanations.

1
2
3
4
5
6
7
8
9
10
buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'com.android.tools.build:gradle:0.7.+'
    }
}
apply plugin: 'android'

Until here no magic, we tell Gradle we need some specifics dependencies to build our project.

1
2
3
4
5
6
repositories {
    mavenCentral()
}
configurations {
    apt
}

The configuration statement defines a dependency group 1. A named dependency group allows you to pick some informations later about the dependencies you define in this group. It is reprensented by an object implementing the Configuration interface 2.

This interface inherits a method named getAsPath which returns the classpath of the dependencies defined in the group as a String. We’ll use this method later to get the classpath of androidannotation annotation compiler.

We create a apt dependency group, to refer to the annotation processor dependencies.

1
2
3
4
5
dependencies {
	compile 'com.android.support:appcompat-v7:+'
	compile 'org.androidannotations:androidannotations-api:3.0'
	apt 'org.androidannotations:androidannotations:3.0'
}

Here we define the dependencies we need in each dependency groups. Within the compile group we add the libraries we need in our builded program. In the apt dependency groups, we add the library needed to process the androidannotations’ annotations.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
android {
    compileSdkVersion 19
    buildToolsVersion "19.0.1"

    defaultConfig {
        minSdkVersion 14
        targetSdkVersion 19
    }
    buildTypes {
        release {
            runProguard false
            proguardFile getDefaultProguardFile('proguard-android.txt')
        }
    }
    productFlavors {
        defaultFlavor {
            proguardFile 'proguard-rules.txt'
        }
    }
    signingConfigs {
        myConfig {
            storeFile file(project.property("MyProject.signing"))
            storePassword "xxxxxxxxx"
            keyAlias "yageek company"
            keyPassword "xxxxxxxxxx"
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.myConfig
        }
    }
}

Simply defines the android SDK we want to use and the minimal API version the application supports and the signing parameters.3

1
2
3
def getSourceSetName(variant) {
    return new File(variant.dirName).getName();
}

We define a simple helper function to retrieve the android source sets variant name.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
android.applicationVariants.all { variant ->
    def aptOutputDir = project.file("build/source/apt")
    def aptOutput = new File(aptOutputDir, variant.dirName)
    println "****************************"
    println "variant: ${variant.name}"
    println "manifest:  ${variant.processResources.manifestFile}"
    println "aptOutput:  ${aptOutput}"
    println "****************************"

    android.sourceSets[getSourceSetName(variant)].java.srcDirs+= aptOutput.getPath()

    variant.javaCompile.options.compilerArgs += [
            '-processorpath', configurations.apt.getAsPath(),
            '-AandroidManifestFile=' + variant.processResources.manifestFile,
            '-s', aptOutput
    ]

    variant.javaCompile.source = variant.javaCompile.source.filter { p ->
        return !p.getPath().startsWith(aptOutputDir.getPath())
    }

    variant.javaCompile.doFirst {
        aptOutput.mkdirs()
    }
}

Let’s divide this in smaller parts:

1
2
3
android.applicationVariants.all { variant ->
	...
}

The changes are applied for all variants (Variant = Build Type + Product Flavor)4 of the application.

1
2
3
4
5
6
7
8
9
android.applicationVariants.all { variant ->
def aptOutputDir = project.file("build/source/apt")
def aptOutput = new File(aptOutputDir, variant.dirName)

println "****************************"
println "variant: ${variant.name}"
println "manifest:  ${variant.processResources.manifestFile}"
println "aptOutput:  ${aptOutput}"
println "****************************"

We first define a outputDirectory for the generated sources. He’re it is set to “build/source/apt” in the aptOutput variable and print some informations to STDOUT.

1
android.sourceSets[getSourceSetName(variant)].java.srcDirs+= aptOutput.getPath()

We add the generated sources to the current variants sources’ scope.

1
2
3
4
5
variant.javaCompile.options.compilerArgs += [
	'-processorpath', configurations.apt.getAsPath(),
    '-AandroidManifestFile=' + variant.processResources.manifestFile,
    '-s', aptOutput
]

For each variant, we access to the gradle java compilation task 5 of each variant and add some arguments to the compiler. Notice the call to getAsPath method as explained before to retrieve the classpath of the androidannotation’s compiler processor. We also set up, the output of processint to aptOutput

1
2
3
variant.javaCompile.source = variant.javaCompile.source.filter { p ->
        return !p.getPath().startsWith(aptOutputDir.getPath())
}

We are filtering the unnecessary files from the task of compiling java’s task.

1
2
3
variant.javaCompile.doFirst {
       aptOutput.mkdirs()
   }

Don’t forget to create aptOutput directory before start the compilation and it’s done.

Setting GOROOT and GOPATH After Installing Go With Homebrew

| Comments

I successfully installed Go by using the simplicity of Homebrew. Installation was fine but some errors occurs with doing a go get command or simply compiling the simple “hello world” program.

After few seconds, I realized how I suck and forget to set up the GOPATH and GOROOT variables.

With Homebrew, the base installation of Go rely under /usr/local/Cellar/go/1.1.2.

Simply set GOROOT to /usr/local/Cellar/go/1.1.2/libexec
In fact, you have to set GOPATH to the directory that contains the src directory that contains the source of go main packages.

Set GOPATH to whatever you want that is different from GOROOT.






Geotagging JPEG With Core Foundation

| Comments

I was searching a way to edit or add GPS metadata of JPEG files without using an external library inside a Mac Application. After looking on internet and reading the ImageIOKit documentation, I found an interesting post on the Apple Mailing List talking about this topic and an old bug related to it. It includes a code sample that is apparently working now (Mac Os X 10.8).  I just wanted to add some details about it :
  • The values corresponding to the kCGImagePropertyGPSLatitudeRef/kCGImagePropertyGPSLongitudedRef keys are expected to be of type NSString.
  • The values corresponding to the kCGImagePropertyGPSLatitude/kCGImagePropertyGPSLongitude keys are expected to be of type NSNumber.

RegexKitLite With Cocoapods

| Comments

I use Cocoapods for managing my Cocoa’s project dependencies. I had an issue with the RegexKitLite. I got an ‘unrecognized selectro send to instance’ issue when I wanted to use a method declared in a category added by RegexKitLite in the NSString interface.

To fix it, add the flags ‘-all_load’ in the Build settings under the ‘Other Linker Flags’ section.

More info : http://stackoverflow.com/questions/2567498/objective-c-categories-in-static-library 

AddSubView, Tag Et Gestion d’UIView Custom

| Comments

Lors d’une petite session de programmation iOS, j’ai voulu créer une vue personnalisée composée de différentes subviews. Je souhaitais gérer les comportements des vues enfants en fonction de leur tags respectifs et mon programme ne réagissait pas comme je le souhaitais. Après un long moment à fouiner dans la doc sans avoir de réponse (si quelqu’un trouve une info, je suis preneur), j’ai trouvé la réponse à mon problème.

Le selecteur addSubview de la classe UIView modifie la valeur des tags des différentes vues que vous passez en arguments. Il vous faut fixer la valeur des tags des différentes vues APRÈS avoir utilisé la méthode addSubview.