3

I have an existing C library, built for Android. I now need to interface with it using JNI. SWIG seems to be a smart way to do this. But all of the SWIG examples I can find build c code into a library which is then wrapped by SWIG.

I have all the headers for the library I have, which is necessary for SWIG to do its work, but I can't figure out how to include the library in the build process of Android Studio.

The gradle build file looks like this for one example project, but I don't see how it knows to include the built .so file into the project.

apply plugin: 'com.android.application'

android {
    compileSdkVersion 21
    buildToolsVersion "21.1.2"

    defaultConfig {
        applicationId "com.sureshjoshi.android.ndkexample"
        minSdkVersion 15
        targetSdkVersion 21
        versionCode 1
        versionName "1.0"

        ndk {
            moduleName "SeePlusPlus" // Name of C++ module (i.e. libSeePlusPlus)
            cFlags "-std=c++11 -fexceptions" // Add provisions to allow C++11 functionality
            stl "gnustl_shared" // Which STL library to use: gnustl or stlport
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:21.0.3'
    compile 'com.jakewharton:butterknife:6.0.0'
}

// Location of where to store the jni wrapped files
def coreWrapperDir = new File("${projectDir}/src/main/java/com/sureshjoshi/core")

task createCoreWrapperDir {
    coreWrapperDir.mkdirs()
}

// For this to work, it's assumed SWIG is installed
// TODO: This only works when called from Command Line (gradlew runSwig)
task runSwig(type:Exec, dependsOn: ['createCoreWrapperDir']) {

    String osName = System.getProperty("os.name").toLowerCase();
    if (osName.contains("windows")) {
        workingDir '/src/main/jni'   // This implicitly starts from $(projectDir) evidently
        commandLine 'cmd', '/c', 'swig'
        args '-c++', '-java', '-package', 'com.sureshjoshi.core', '-outdir', coreWrapperDir.absolutePath, 'SeePlusPlus.i'
    }
    else {
        commandLine 'swig'
        args '-c++', '-java', '-package', 'com.sureshjoshi.core', '-outdir', coreWrapperDir.absolutePath, "${projectDir}/src/main/jni/SeePlusPlus.i"
    }

}
Almo
  • 14,789
  • 13
  • 64
  • 91

1 Answers1

1

The example code you're using is mine, so maybe I can help :)

The library itself is statically loaded into the project in the MainActivity (or MainApplication, whatever). Make sure your libraries end up in the correct location

static {
    // Use the same name as defined in app.gradle (do not add the 'lib' or the '.so')
    System.loadLibrary("SeePlusPlus");
}

In my NDK example, you'll see after building, the .so files end up in android-ndk-swig-example/NDKExample/app/build/intermediates/ndk/debug/lib/

If you have your own .so files, I believe they need to go into the app/src/main/jniLibs/[architecture] folder... You can put them there, then try the loadLibrary, and if the app crashes, it's incorrect.

Similarly, check out this answer - specifically the talk about sourcesets (default should be jniLibs, but you can mod it): https://stackoverflow.com/a/26693354/992509

Community
  • 1
  • 1
SJoshi
  • 1,559
  • 18
  • 43
  • I browse thru it for a few minutes as I am deciding. Seems that this Esperanto-like mechanism is making things harder than it needs to be. A black box + headers? Seems like recipe for disaster – eigenfield Mar 07 '20 at 11:18
  • @truthadjustr It definitely has pros/cons - but black box + headers is kinda the C++ way for libraries :) There are enough compile-time errors to not mess it up too badly, and maybe now a few years later there are better solutions, but not that I've seen. I've come up with a few different methods over the years, each has issues. No perfect solution that is safe, readable, maintainable, modifiable unfortunately. – SJoshi Jun 26 '20 at 13:56