user3342339
user3342339

Reputation: 377

Android Studio, gradle, ndk, aar and the inclusion of several native shared libraries

I pretty much read through almost every question in stackoverflow about the subject. I browsed documentation and work-notes of other people who are using AS + NDK + gradle to build an aar that would be included by other app.

I was able to build the .so in a different multi-project setup where the structure was different from the one shown in one aspect: it didn't have the first jni/ layer.
I added that extra jni layer so that I'd have a sharedObjectLib#2/ hierarchy. In that jni/ dir, all i have is a single Android.mk whose sole purpose is to include $(call all-subdir-makefiles). After I did that, gradle build reports the NDK failure: "Error:(89) Android NDK: WARNING: There are no modules to build in this project!"

What I can't seem to be able to do is build multiple shared objects '.so' as part of the aar.

I would really like to know if (a) it is doable; and (b) some pointers to links and/or examples of gradle.build files that actually do that.

Here is the structure I currently have - skipping the usual directories created by Android Studio (v. 1.2.2, btw).

--rootProject/
--build.gradle
--gradle.properties
--local.properties
--settings.gradle
--rootProject.iml
--app/
--moduleProjectThatBuildsAAR/
--build.gradle
--build/
--libs
--src/
    --main/
        --res/
        --AndroidManifest.xml
        --jni/
            --Android.mk (does include $(call all-subdir-makefiles)) 
            --Application.mk
            --sharedObjectLib#1/
                --build.gradle
                --src/
                    -- androidTest/
                    -- main/
                        --java/
                        --jni/
                            -- Android.mk
                            -- Application.mk
                            -- *.c and *.h files
                        --libs/
                        --obj/
                    -- build.gradle

It's pretty convoluted and I am hoping the experts would help with simplification.

thanks!

Upvotes: 1

Views: 1684

Answers (1)

TeasingDart
TeasingDart

Reputation: 381

I am using 1.2.2 and found it easy to build the simple NDK projects from the many tutorials floating around, but frustratingly difficult to build an NDK project of any complexity. I will summarize what I found, but I highly suggest reading this blog and this StackOverflow.

I found that Android Studio would completely ignore the Android.mk file I created, and instead auto-generate its own. To correct this, I had to first hack the build.gradle script for my project, located at project/app/build.gradle. You could probably hack the top-level build.gradle, if desired.

This may be what is happening in your case. The auto-generated Android.mk looks in jni/ for .c source files and finds nothing there.

This is my build.gradle. I build on a Windows box, so I hacked it for Windows only. Uncomment the lines if you are using OSX or Linux.

project/app/build.gradle:

//import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.application'

android {
  compileSdkVersion 22
  buildToolsVersion "22.0.1"

  defaultConfig {
    applicationId "com.sample.app"
    minSdkVersion 15
    targetSdkVersion 22
    versionCode 1
    versionName "1.0"
  }
  buildTypes {
    release {
      minifyEnabled false
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }

  //ENABLE CUSTOM ANDROID.MK >>
  sourceSets.main.jni.srcDirs= [] //Disable automatic ndk-build.
  sourceSets.main.jniLibs.srcDir 'src/main/libs'

  //Call regular ndk-build script from app directory
  task ndkBuild(type: Exec) {
    workingDir file('src/main')
    commandLine getNdkBuildCmd()
  }

  tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn { ndkBuild }
  }

  task cleanNative(type: Exec) {
    workingDir file('src/main')
    commandLine getNdkBuildCmd(), 'clean'
  }

  clean.dependsOn cleanNative
}
//ENABLE CUSTOM ANDROID.MK <<

dependencies {
  compile fileTree(dir: 'libs', include: ['*.jar'])
  compile 'com.android.support:appcompat-v7:22.2.0'
  compile 'com.google.android.gms:play-services:7.5.0'
}

//ENABLE CUSTOM ANDROID.MK >>
def getNdkDir() {
  if (System.env.ANDROID_NDK_ROOT != null)
    return System.env.ANDROID_NDK_ROOT

  Properties properties = new Properties()
  properties.load(project.rootProject.file('local.properties').newDataInputStream())
  def ndkdir = properties.getProperty('ndk.dir', null)
  if (ndkdir == null)
    throw new GradleException("NDK location not found. Define location with ndk.dir in the local.properties file")

  return (ndkdir)
}

def getNdkBuildCmd() {
  def ndkbuild = getNdkDir() + "/ndk-build.cmd"
//  def ndkbuild = getNdkDir() + "/ndk-build"
//  if (Os.isFamily(Os.FAMILY_WINDOWS))
//    ndkbuild += ".cmd"
  return ndkbuild
}
//ENABLE CUSTOM ANDROID.MK <<

Upvotes: 2

Related Questions