KISS

Keep It Simple Stupid

gradle: auto detect android SDK and build tools versions

| comments

Gradle is the new build system for android apps. In the build script you need to specify what SDK and build tools versions to use, and if a new developer or customer doesn’t have that exact version installed, when importing into Android Studio, they’ll hit an error message like failed to find target android-18. Or that’s the case when a bunch of developers have different versions installed. You probably don’t want to make changes in the build.gradle file all the time. So I wrote a couple of functions on Groovy to automagically select the latest versions available.

Here’s the code:

(build_sdk.gradle) download
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
70
71
72
73
74
75
76
77
78
// http://www.egeek.me/
import org.codehaus.groovy.runtime.StackTraceUtils

int[] sdksAvailable() {
    def sdks = new ByteArrayOutputStream()
    exec {
        commandLine 'android', 'list'
        standardOutput = sdks
    }
    sdks = sdks
            // get the output
            .toString()
            // split to strings
            .split('\n')
            // leave only strings with API levels
            .findAll { it ==~ /\s*API level:.*/ }
            // extract the API levels
            .collect { (it =~ /\s*API level:\s*(\d+).*/)[0][1].toInteger() }
            // sort from highest to lowest
            .sort( { a, b -> b <=> a } )
    sdks
}

int highestSdkAvailable(int defaultSdk) {
    try {
        def sdks = sdksAvailable()
        def highestSdk = sdks[0]
        if (highestSdk != null) {
            println "Using highest found SDK " + highestSdk
            highestSdk
        } else {
            println "No installed SDKs found. Using default SDK " + defaultSdk
            defaultSdk
        }
    } catch (any) {
        println "Exception while determining highest SDK. Using default SDK " +
                defaultSdk
        StackTraceUtils.sanitize(any).printStackTrace()
        defaultSdk
    }
}

String androidSDKDir() {
    def androidExecPath = new ByteArrayOutputStream()
    exec {
        commandLine 'which', 'android'
        standardOutput = androidExecPath
    }
    file(androidExecPath.toString().trim()).getParentFile().getParentFile()
}

String[] buildToolsAvailable() {
    def buildToolsDir = new File(androidSDKDir(), "build-tools")
    buildToolsDir.list().sort { a, b -> b <=> a }
}

String latestBuildToolsAvailable(String defaultBuildTools) {
    try {
        def buildToolsVersions = buildToolsAvailable()
        def latestBuildTools = buildToolsVersions[0]
        if (latestBuildTools != null) {
            println "Using latest found build tools " + latestBuildTools
            latestBuildTools
        } else {
            println "No installed build tools found. Using default build tools " +
                    defaultBuildTools
            defaultBuildTools
        }
    } catch (any) {
        println "Exception while determining latest build tools. Using default build tools " +
                defaultBuildTools
        StackTraceUtils.sanitize(any).printStackTrace()
        defaultBuildTools
    }
}

ext.compileSdkVersion = highestSdkAvailable(19)
ext.buildToolsVersion = latestBuildToolsAvailable("19.0.0")

The script relies on some assumptions that are true for now. E.g., the relative path from the android executable to where different build tools are installed: ../../build-tools/. I couldn’t find a better way to get a list of available tools.

To use it, you need to copy the contents into your project’s build.gradle file. If you have only one module in the project, remove the ext. part from the two bottom lines. Otherwise, here’s the explanation: http://stackoverflow.com/questions/19849086/specify-versioncode-in-android-gradle-projects-project-root-build-gradle/19856791#19856791.

Comments