«

»

Dec 04

Disabling Gradle auto build in Android Studio and set to use Make Files

Disabling Gradle auto build in Android Studio and set to use Make Files

 

 

Theoretical background:

 
 

To build using a custom Android MakeFile:

If you would like to use a custom android MakeFile instead of using the default compilation of Gradle, we will have to:

 

1. Create a custom Android.mk file and a custom Application.mk file in the app/jni folder of our project.

 

2. Disable the Gradle support auto generation of the Application.mk and Android.mk files.

 

3. Set Gradle to also build the native part of our application: to call the ndk-build tool to compile our project using the Application.mk and Android.mk files we created,

 

4. Set Gradle to call the native build when we build the java code from AndroidStudio, and also to clean the native compiled files during the AndroidStudio java clean operation. This way, instead of having to use the command line to manually run the ndk-build script, when we clean and build from Android Studio, it will also clean and build the native code.

 

In this article we will not learn about the Application.mk and Android.mk, as we did that in the previous article. In this article we will learn how to connect Gradle to these Make files and set Gradle tasks that will build and clean the Native code as well when building / cleaning our project from Android Studio.

 

1. Create a custom Android.mk file and a custom Application.mk

We did that in the previous article.

 

2. Disable the Gradle support auto generation of the Application.mk and Android.mk files:

In order to disable it first lets set up our ndk.dir path in the local.properties file as such:

ndk.dir=E\:\\android\\android-ndk-r10d

(Replace with your own path of the ndk folder)

 

Now we will need to add the following configuration to Gradle, telling it that we will use a custom MakeFile and so Gradle will not generate an automatic Application.mk and Android.mk:

 

    //**********************************************************************************************
    // We defined to get the properties we defined in the file "local.properties"

    Properties properties = new Properties()
    properties.load(project.rootProject.file('local.properties').newDataInputStream())

    // This is the root folder of our project
    def RootFolder = file('../../..').absolutePath

    //**********************************************************************************************
    // Disable Gradle's auto generation of Android.mk and Application.mk
    // This allows us to use our custom make files.

   // Base dir where the ndk build will output the compiled files
   // This path can not be too long, this is already almost at the max length for the path, it won't compile if it is too long
    def ndkOutputDir = RootFolder.toString() + "/Android/CrossPlatformProjectExample/app/ndkOut"

   // Where the ndk build will output the compiled lib files
    Def ndkOutputLibDir = ndkOutputDir + "/libs"

   sourceSets.main {
   // This prevents the auto generation of Android.mk and Application.mk by Gradle
   // Instead, we invoke the NDK build process using a custom Gradle task and supply our own make files
	jni.srcDirs = []

  // We tell gradle to take the *.so files from this directory
  // By doing so, Gradle will package them into the output apk file.
  // This directory should be where the ndk build compiled the libs files to
	jniLibs.srcDirs = [ndkOutputLibDir]
   }

 

The line

jniLibs.srcDirs = [ndkOutputLibDir]

Defines where to take the compiled *.so files from, in the next part we will set the output lib of the ndk-build to this folder

 

3. Set Android Studio to build and clean the native code:

 

    //**********************************************************************************************
    // Setup the NDK build
    // For more info about the ndk-build command: http://developer.android.com/ndk/guides/ndk-build.html

    // Where the ndk build will output the compiled obj files
    def ndkOutputObjDir = ndkOutputDir + "/obj"

    // Resolve NDK locations/paths
    def ndkDir = properties.getProperty('ndk.dir')
    def ndkBuildPath = ndkDir.toString() + '/ndk-build.cmd'

    // Gradle calls the ndk-build.cmd script from the app directory
    // Setting the buildNative task to take dependency on the generateSWIGFiles task
    task buildNative(type: Exec, description: 'Compile JNI source via NDK') {

        commandLine ndkBuildPath,
                '-C', file('jni').absolutePath, // Sets from where to run the command (instead of cd to our project path) this is from the folder
                // where the jni folder exists - the android project root path
                '-j', (Runtime.getRuntime().availableProcessors() - 1).toString(), // Allow up to N-1 parallel compilation jobs
                'NDK_OUT=' + ndkOutputObjDir, // Where to place the obj files resulted from the compilation
                'NDK_LIBS_OUT=' + ndkOutputLibDir, // Where to place the libs files resulted from the compilation
                'NDK_DEBUG=1' // This forces a debuggable version, when we release the version to the app we can remove this option
    }

    // Make Gradle clean also the generated outputs from the build native task:
    // The CrossPlatformProjectExample\app\libs and CrossPlatformProjectExample\app\obj
    task cleanNative(type: Exec, description: 'Clean the compiled files that were generated during the ndk build')       {
        commandLine ndkBuildPath, // Sets from where to run the command (instead of cd to our project path) this is from the folder
                // The path of the jni folder - the android project root path
                '-C', file('jni').absolutePath,
                'NDK_OUT=' + ndkOutputObjDir,
                'NDK_LIBS_OUT=' + ndkOutputLibDir,
                'clean'
    }

 

Note:

When we create the Android.mk and the Application.mk we need to place them in a folder named jni and run the ndk-build from the folder above the jni folder, this way the ndk-build will automatically use the Android.mk and the Application.mk we placed in the jni folder.

In general – we can call ndk-build(.cmd) from any path we choose, it will search for the make files in a subfolder “jni”.

In our example we run the ndk-build from our root folder, which the jni folder (containing the Application.mk and Android.mk files) is.

 

4. Set Gradle to call the native build when we build the java code from AndroidStudio, and also to clean the native compiled files during the AndroidStudio java clean operation:

    //**********************************************************************************************
    // Setting build and clean dependencies
	
    buildNative.dependsOn 'generateSWIGFiles'

    // Sets the default clean tas from AndroidStudio to be dependable upon the cleanNative task we created
    // This way when we clean the project it will also clean the native part of our project
    // This is not a must and not recommended if the c++ code is large and you usually only work on the Java code
    clean.dependsOn 'cleanNative'

    // Sets the default build task from AndroidStudio to be dependable upon the buildNative task we created
    // This way when we clean the project it will also clean the native part of our project
    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn buildNative
    }

    //**********************************************************************************************

 

This line:

buildNative.dependsOn ‘generateSWIGFiles’

Sets a dependency that before building the native code, we will generate the SWIG files.

The SWIG part of the native project will be explained in the next article.

 
 

Good luck !

Leave a Reply

Your email address will not be published.

אתם יכולים להשתמש באפשרויות ותגי ה-HTMLהבאים: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>