6

After spending hours and hours searching for a solution to my problem and browsing the various forums (including this one) i finally decided to ask my question, hoping that it has not been fully answered elsewhere.

I'm trying to build a pretty complex architecture :

  • I have C sources that i compile in separates static libraries (.a)
  • I use them via JNI in a module Library
  • I want to use this library in an app project.

I first successfully did the following tests - I already managed to make a module library without NDK and compile it with the app. - I also managed to use the static libraries and JNI directly in the app but

I am failing with the following step : - The combination of JNI inside the module and app calling the classes of the module doesn't work.

I think the problem is with the include of the aar, because I can't find the exploded-aar in the build directory of my app while the aar is in the library build/outputs directory. Besides, all the previous tests (including the use of JNI were successful).

I'm not using the experimental model because it is experimental and there are known limitations with static libraries.

The structure of my project is :

- App
    - src
        - main
            - java
                - activity  
- bar
    - src
        - main
            - java
                - class
            - jni
                - include
                    - *.h
                - libs
                    - abis...
                        - libmod1.a
                        - libmod2.a
                Android.mk
                Application.mk
                bar.c
                bar.h

The app build.gradle looks like this :

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.0"

    defaultConfig {
        applicationId "com.test.foo"
        minSdkVersion 10
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }

    buildTypes {

        release {
            debuggable          false
            jniDebuggable       false
            minifyEnabled       false
        }
        unsigned {
            debuggable          false
            jniDebuggable       false
            minifyEnabled       false
        }
        debug {
            debuggable          true
            jniDebuggable       true
            minifyEnabled       false
        }
    }


    productFlavors {
        x86 {
            ndk {
                abiFilter "x86"
            }
        }
        mips {
            ndk {
                abiFilter "mips"
            }
        }
        armv7 {
            ndk {
                abiFilter "armeabi-v7a"
            }
        }
        arm {
            ndk {
                abiFilter "armeabi"
            }
        }
        fat
    }

    project.ext.versionCodes = ['armeabi':1, 'armeabi-v7a':2, 'arm64-v8a':3, 'mips':5, 'mips64':6, 'x86':8, 'x86_64':9]

    android.applicationVariants.all { variant ->
        variant.outputs.each { output ->
            output.versionCodeOverride =
                    project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + defaultConfig.versionCode
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar','*.aar'])
    compile project( ":bar" )
}

The module build.gradle looks like this :

apply plugin: 'com.android.library'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.0"

    defaultConfig {
        minSdkVersion 10
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"

        ndk {
            moduleName "module"
        }
    }
    buildTypes {

        release {
            debuggable      false
            jniDebuggable   false
            minifyEnabled   false
        }
        unsigned {
            debuggable      false
            jniDebuggable   false
            minifyEnabled   false
        }
        debug {
            debuggable      true
            jniDebuggable   true
            minifyEnabled   false
        }
    }

    productFlavors {
        x86 {
            ndk {
                abiFilter "x86"
            }
        }
        mips {
            ndk {
                abiFilter "mips"
            }
        }
        armv7 {
            ndk {
                abiFilter "armeabi-v7a"
            }
        }
        arm {
            ndk {
                abiFilter "armeabi"
            }
        }
        fat
    }
    sourceSets.main {
        jniLibs.srcDir 'src/main/libs'
        jni.srcDirs     = []
    }

    task ndkBuild(type: Exec) {
        commandLine android.ndkDirectory.getAbsolutePath()+'/ndk-build', '-C', file('src/main').absolutePath
    }

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

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

My Android.mk inside the module jni directory is : LOCAL_PATH:= $(call my-dir)

#### Mod1
include $(CLEAR_VARS)
LOCAL_MODULE            := mod1
LOCAL_SRC_FILES         := libs/$(TARGET_ARCH_ABI)/libmod1.a
include $(PREBUILT_STATIC_LIBRARY)

#### Mod2
include $(CLEAR_VARS)
LOCAL_MODULE            := pxnav
LOCAL_SRC_FILES         := libs/$(TARGET_ARCH_ABI)/libmod2.a
LOCAL_STATIC_LIBRARIES  := pxfd
include $(PREBUILT_STATIC_LIBRARY)

##### Parser
include $(CLEAR_VARS)
LOCAL_MODULE            := module
LOCAL_C_INCLUDES        := $(LOCAL_PATH)/include
LOCAL_LDLIBS            += -landroid -llog
LOCAL_SRC_FILES         := bar.c
LOCAL_STATIC_LIBRARIES  := mod1 mod2
include $(BUILD_SHARED_LIBRARY)
  • I add that if i use the generated aar directly : New module > Import .jar/.aar it works perfectly aswell. I would prefer not to have to copy the aar to a specified directory each time i compile though. – William Depoitte Oct 02 '15 at 12:21

1 Answers1

0

I found an easy workaround for similar task: I simply set jniLibs.srcDir for the app module. Now I don't depend on exploding the aar to get the .so files in place. BTW, when you decide to switch to experimental plugin (to use native debugging, C++ syntax highlighting and cross-references and other niceties), you are invited to check define LOCAL_SRC_FILES in ndk{} DSL.

Community
  • 1
  • 1
Alex Cohn
  • 56,089
  • 9
  • 113
  • 307
  • I don't understand how it helps. You set the jniLibs.srcDir inside the app to the libs directory inside the module ? In that case how do you manage to make the app see the classes in the aar ? My problem is that even the class in the bar module library is not usable in the app. – William Depoitte Oct 02 '15 at 12:18
  • I tried your solution, I indeed have the libs linked in my APK but the classes of the AAR are still missing from the APK and cant be instantiated in the app. – William Depoitte Oct 02 '15 at 13:46
  • The library does not build its native code; it pretends to be a pure Java module. You said that you succeeded to use a library in one of your preliminary experiments, didn't you? – Alex Cohn Oct 02 '15 at 13:49
  • Oh i get it. You advise that the NDK code should not be compiled in the AAR but in the APK and i would link a NDK-free AAR ? Well i guess it works, but i'd rather have an AAR fully fonctionnal (which works if i import the AAR as a module). – William Depoitte Oct 02 '15 at 14:27
  • You mean, this works as long as the library is an external *Module*; but if you have this library *Module* part of the *Project*, and this *Module* involves native code, then gradle plugin does not handle exploded AAR correctly? – Alex Cohn Oct 02 '15 at 14:50