Android Native Library Module (and Debug)

Adding some C++ to an existing Android project? Good news is that Android Studio support for C++ is getting better every day, and you can now even debug native code together with Java code. Bad news is that you will most surely need to use the experimental version of Gradle.
For a new project, you can just use the newest experimental gradle version. After using it in a couple of production apps, it clearly is stable enough; even if something goes wrong, it will do so either during the compilation or on the first run. For an existing project, consider the possibility of migrating your whole project to the experimental gradle version. It should not be too complicated. At last, if using the experimental gradle for your whole project is not possible, you will also be fine by mixing gradle versions. You can just use the estable version of gradle for the main module and then use any gradle version for each of the other modules, so just create a library-module for that C++ code to live in and compile it using the experimental gradle.

Fast forward

For the impatient, just check the example project I uploaded to Github (doesn’t get much simpler than that):

https://github.com/akaita/AndroidNativeLibrary

A library module with experimental gradle

Create a normal library module, plus:
Make sure the project’s build.gradle contains both gradle’s:

dependencies {
    classpath 'com.android.tools.build:gradle:2.1.0'
    classpath 'com.android.tools.build:gradle-experimental:0.7.0'
}

The Android guys have been very nice and used different namespaces for both the stable and the experimental graversion. This way you can use the stable gradle in configurations with apply plugin: 'com.android.application' , and the experimental one in configurations with apply plugin: 'com.android.model.library'.

Beware: some versions of the stable and experimental gradle are not compatible. If you you want to use any combination other than gradle:2.1.0 and gradle-experimental:0.7.0, you will have to try them out. Luckily, you’ll learn about any incompatibility at compile time.

The library’s build.gradle will look similar to this:

apply plugin: 'com.android.model.library'

model {
    android {
        compileSdkVersion = 18
        buildToolsVersion = "23.0.1"

        defaultConfig.with {
            minSdkVersion.apiLevel = 15
            targetSdkVersion.apiLevel = 18
        }
    }

    android.ndk {
        moduleName = "NativeCode"

        // add compilation flags
        cppFlags.add("-DANDROID")
        cppFlags.add("-frtti")
        cppFlags.add("-std=c++11")
        cppFlags.add("-fexceptions")

        // include headers
        cppFlags.add("-I${file("native-src")}".toString())

        ldLibs.addAll("android", "dl", "log", "z", "atomic")

        stl = "c++_static"  // LLVM compiler
    }

    android.sources {
        main {
            jni {
                source {
                    // C and C++ source code
                    srcDirs += 'native-src'
                }
            }
        }
    }

    android.buildTypes {
        debug {
            ndk.with {
                cppFlags.add("-D_DEBUG")

                abiFilters.add("armeabi-v7a")
                abiFilters.add("x86")

            }
        }
        release {
            ndk.with {
                abiFilters.add("armeabi-v7a")
                abiFilters.add("x86")
            }
        }
    }
}

With this, you should be set to know how to mix stable and experimental versions of the gradle plugin for Android.

Enable debugging of library module

Odly enough, Android’s build system will always compile library-modules in Release, even if the module making use of them. This means you can’t debug library-modules when invoked from another module. This would make any development very very hard, so I found a way to do debug C++ code in library-modules (you should really send me a beer if you are reading this, just saying).
First, specifically tell Android Studio that you will want to debug JNI/C by adding this to the main module’s build.gradle:

android.buildTypes {
    debug{
        debuggable true
        jniDebuggable true
    }

Now, to make gradle build the debuggable version of the library-module but still use the non-debuggable one for Release, in the main module’s build.gradle:

dependencies {
    releaseCompile project(path: ':native', configuration: 'release')
    debugCompile project(path: ':native', configuration: 'debug')
}

To allow the library-module to be built in Debug, in the library-module’s build.gradle:

android {
    publishNonDefault true
}

To expose the Debug version of the library-module to the main module, in the library-module’s build.gradle:

configurations {
    // Expose the debug version of the library to other modules
    debug
    release
}

And there you are, you can now debug you library-module’s JNI bit, C bits, C++ bits,… everything :)

Note: Android Studio 2.2 is currently smart enough to know that it should use the hybrid debugger for this. Android Studio 2.1 needs you to edit the Run Configuration and choose the Hybrid Debugger.

© 2017 Akaita development