145

I am trying my hands on developing a simple android application in which I am trying to use sqlcipher, which uses .so libraries internally. I have read the documentation on how to use sqlcipher with android app. I have followed the steps and it compiles without any error. But, at runtime it throws UnsatisfiedLinkError.

Googling around for it, I found that, gradle doesn't support .so libraries yet, but I found a hack here which I am trying to use. But it throws compile time error at line #40 on the gist which is,

tasks.withType(com.android.build.gradle.PackageApplicationTask) { pkgTask ->
    pkgTask.jniDir new File(buildDir, 'native-libs')
}

saying

Could not find property 'com' on Project 'MyProject'

Here I am posting code from my build.gradle file.

buildscript {
    repositories {
        maven { url 'http://repo1.maven.org/maven2' }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.4'
    }
}
apply plugin: 'android'

dependencies {
    compile files('libs/android-support-v4.jar')
    compile files('libs/commons-codec.jar')
    compile files('libs/guava-r09.jar')
    compile files('libs/sqlcipher.jar')
}

targetCompatibility = 1.6
sourceCompatibility = 1.6

android {
    target = 'android-14'

    compileSdkVersion 17
    buildToolsVersion "17.0.0"

    defaultConfig {
        minSdkVersion 9
        targetSdkVersion 16
    }    

}

task copyNativeLibs(type: Copy) {
    from(new File(project(':MyProject').buildDir, 'native-libs')) { include '**/*.so' }
    into new File(buildDir, 'native-libs')
}

tasks.withType(Compile) { compileTask -> compileTask.dependsOn copyNativeLibs }

clean.dependsOn 'cleanCopyNativeLibs'

tasks.withType(com.android.build.gradle.PackageApplicationTask) { pkgTask ->
    pkgTask.jniDir new File(buildDir, 'native-libs')
}

Can, anybody please help me on what I have done wrong or what should I do to include those .so libraries in my apk?

As I am new to android development and gradle, please apologize me if I have misunderstood something.

Rumit Parakhiya
  • 2,674
  • 3
  • 24
  • 33

3 Answers3

257

I've tried the solution presented in the accepted answer and it did not work for me. I wanted to share what DID work for me as it might help someone else. I've found this solution here.

Basically what you need to do is put your .so files inside a a folder named lib (Note: it is not libs and this is not a mistake). It should be in the same structure it should be in the APK file.

In my case it was:
Project:
|--lib:
|--|--armeabi:
|--|--|--.so files.

So I've made a lib folder and inside it an armeabi folder where I've inserted all the needed .so files. I then zipped the folder into a .zip (the structure inside the zip file is now lib/armeabi/*.so) I renamed the .zip file into armeabi.jar and added the line compile fileTree(dir: 'libs', include: '*.jar') into dependencies {} in the gradle's build file.

This solved my problem in a rather clean way.

Assaf Gamliel
  • 11,935
  • 5
  • 41
  • 56
  • best answer until the support in studio is there – dskinner Jul 23 '13 at 20:19
  • in debug BuildType everything works perfectly, but when I added proguard in release BuildType , a library can't load the log is `No JNI_OnLoad found in /data/data/com.hotelvp.caoniu/lib/liblocSDK3.so 0x41d7e268, skipping init`. I unzip the apk, `lib/armeabi/liblocSDK3.so` exists. do you have a similar problem? – aelam Sep 09 '13 at 06:54
  • @AssafGamliel Cool, but how do you work around the first compilation not finding the armeabi.jar dependency? Do you just build twice? – snowdragon Sep 10 '13 at 15:38
  • @aelam: I didn't have a similar problem, make sure the hierarchy of files are correct. – Assaf Gamliel Sep 11 '13 at 06:37
  • @snowdragon: I think I used clean and then build. – Assaf Gamliel Sep 11 '13 at 06:37
  • Is this still the best method? Or has Android Studio added support since? – SteveEdson Oct 29 '13 at 10:53
  • 1
    When I updated Android Studio to 0.3.2 (on Mac), the problem occurred. It's a strange problem, this resolution works perfectly. – chris Nov 04 '13 at 08:42
  • That's work for me !!! (Android Studio 0.3.5, gradle 0.6.+) – prcaen Nov 18 '13 at 16:41
  • For me the line was already there, so I just had to zip. – weston Nov 27 '13 at 14:32
  • I can confirm that this workaround indeed works - oddly enough it does not work for other archives like tar.bz2 - it seems they are silently ignored! Lets hope the Android Gradle plugin will handle this sooner rather than later... – slott Dec 11 '13 at 21:56
  • I have posted my answer in the below mentioned link http://stackoverflow.com/questions/20900814/add-pre-built-so-files-in-project-using-gradle-0-7-3 – Ahmad Ali Nasir Jan 06 '14 at 11:28
  • 12
    after wasting hours on this (stupid) thing, i can state that you SIR DESERVE A BEER! –  Mar 03 '14 at 01:24
  • @AssafGamliel thank you so much for the answer, but I am still getting an UnsatisfiedLinkError at runtime. I believe it has something to do with my file structure because I am confused if I should be putting the lib folder at the top level of my project or in my "app" module. If you could take a look at my project structure here, it would be greatly appreciated: http://i.imgur.com/4nENTdm.png – Dick Lucas Apr 02 '14 at 15:42
  • 3
    @Richard Did you clean the project after setting it up as described? – Assaf Gamliel Apr 02 '14 at 16:40
  • @AssafGamliel I did, but the error still persists. I don't understand how the "compile fileTree(dir: 'libs', include: '*.jar'" line makes sense if I do not have an folder actually named "libs". I only have the "lib" folder. – Dick Lucas Apr 02 '14 at 22:29
  • @AssafGamliel Wow, I was an idiot. I put the armeabi.jar file with the structure you told us to, and just had to put that in a folder called "libs". Thanks for your help. – Dick Lucas Apr 02 '14 at 22:43
  • Why isn't the accepted answer? @Rumit Parakhiya – webo80 Nov 04 '14 at 12:12
  • Thank you :), I don't know you but I appreciate it :D. Glad I could help. – Assaf Gamliel Dec 16 '14 at 07:32
  • Worked for me too, using Android Studio 1.1.0 – Gustav Apr 17 '15 at 14:20
  • This worked for me on Android Studio 1.2.2, thank you – kaay Jul 09 '15 at 07:25
  • This stopped working for me with gradle > 1.3. Check Riyaz Mohammed Ibrahims comment above - it woirks perfectly! – de. Jan 13 '16 at 12:52
  • 2
    This is working for me too but i am getting the error on marshmallow. i.e., "file not fount libtbb.so" Please help me. – Hemant Dubey May 19 '16 at 09:51
  • java.lang.UnsatisfiedLinkError: No implementation found for java.lang.String – Rohit Mandiwal Aug 14 '16 at 13:00
  • i have .so file of other app that i have decompile i don't have native-lib.cpp file of that .so means i don't have native code i only have .so can i integrate and run it in my project because when i m runing the project this error is coming java.lang.UnsatisfiedLinkError: No implementation found for int com.krunal.camarademo.Libs.nativesystem.DMDHDR.getBracketedCount() (tried Java_com_krunal_camarademo_Libs_nativesystem_DMDHDR_getBracketedCount and Java_com_krunal_camarademo_Libs_nativesystem_DMDHDR_getBracketedCount__) – karan Jan 09 '23 at 11:19
68

To include native libraries you need:

  1. create "jar" file with special structure containing ".so" files;
  2. include that file in dependencies list.

To create jar file, use the following snippet:

task nativeLibsToJar(type: Zip, description: 'create a jar archive of the native libs') {
    destinationDir file("$buildDir/native-libs")
    baseName 'native-libs'
    extension 'jar'
    from fileTree(dir: 'libs', include: '**/*.so')
    into 'lib/'
}

tasks.withType(Compile) {
    compileTask -> compileTask.dependsOn(nativeLibsToJar)
}

To include resulting file, paste the following line into "dependencies" section in "build.gradle" file:

compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar')
Lucifer
  • 29,392
  • 25
  • 90
  • 143
Ruslan Yanchyshyn
  • 2,774
  • 1
  • 24
  • 22
  • 29
    `Compile` task has been deprecated. Use `JavaCompile` instead. – Nick Caballero Sep 20 '13 at 14:06
  • 2
    I used this answer over Assaf's answer because it makes it an automated process. Additionally, there are many ways to manually make a zip file, and some of those methods introduce unnecessary files. – Jeremy Sep 26 '13 at 00:18
  • 3
    This doesn't really work for me because on a clean build (`./gradlew clean`), native-libs.jar isn't included in the first build after clean (inside the APK). Later builds (if not cleaned) work fine. This is somewhat of a problem for our build server script. Anyone has any solution for this? I'm currently using Gradle (wrapper) 1.8 and "com.android.tools.build:gradle:0.6.3". – croc Dec 09 '13 at 11:05
  • 37
    As of Android Gradle 0.7.2 you can put your native libraries in src/main/jniLibs and they'll be packaged correctly. Sample : https://github.com/commonsguy/sqlcipher-gradle/tree/master/src/main/jniLibs – Riyaz Mohammed Ibrahim Jun 11 '14 at 06:28
  • 8
    Add following to build.gradle: sourceSets { main { jniLibs.srcDirs = ['libs'] } } – herbertD Jun 17 '14 at 03:49
  • @Riyaz Mohammed Ibrahim, this should be an answer. It is hard to find in the comments area. – yorkw Jul 09 '14 at 08:24
  • @RiyazMohammedIbrahim has the answer.. this was is SO much more simple! – Jeremy Jul 16 '14 at 16:23
  • @RiyazMohammedIbrahim Maybe wanna put this as an answer? I searched long for it and still apply's on gradle 1.0.0. – Ostkontentitan Feb 06 '15 at 13:42
  • @all since this answer is marked as duplicate I can't answer now, you guys can upvote my comment so it will come up so others can easily find out – Riyaz Mohammed Ibrahim Feb 27 '15 at 17:55
  • Correction use `JavaCompile` instead of `Compile`. It worked for me at least: `tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn(nativeLibsToJar) }` – abggcv Feb 03 '18 at 18:02
  • i have .so file of other app that i have decompile i don't have native-lib.cpp file of that .so means i don't have native code i only have .so can i integrate and run it in my project because when i m runing the project this error is coming java.lang.UnsatisfiedLinkError: No implementation found for int com.krunal.camarademo.Libs.nativesystem.DMDHDR.getBracketedCount() (tried Java_com_krunal_camarademo_Libs_nativesystem_DMDHDR_getBracketedCount and Java_com_krunal_camarademo_Libs_nativesystem_DMDHDR_getBracketedCount__) – karan Jan 09 '23 at 11:19
  • where to put the task .. and how to run the script to convert it into jar? – Rohit gupta Apr 27 '23 at 13:34
27

I had the same problem. Check out the comment in https://gist.github.com/khernyo/4226923#comment-812526

It says:

for gradle android plugin v0.3 use "com.android.build.gradle.tasks.PackageApplication"

That should fix your problem.

Paglian
  • 6,162
  • 3
  • 26
  • 20
  • Works in v0.4 as well, although I had to modify the copy command's "from" to grab the so files out of the project directory instead of the build directory. – J c May 27 '13 at 23:54
  • I had to change the project(':MyProject').buildDir to project(':MyProject').getProjectDir() to make it work, using Android studio 0.3.6 and com.android.tools.build:gradle:0.6.+ – nilsmagnus Nov 20 '13 at 20:06
  • 25
    As of Android Gradle 0.7.2 you can put your native libraries in src/main/jniLibs and they'll be packaged correctly. Sample : https://github.com/commonsguy/sqlcipher-gradle/tree/master/src/main/jniLibs – Riyaz Mohammed Ibrahim Jun 11 '14 at 06:28
  • Right answer is http://stackoverflow.com/questions/16667903/android-studio-gradle-and-ndk/25067178#25067178 – sagus_helgy Jul 31 '14 at 19:22
  • @RiyazMohammedIbrahim has by far the simplest approach for getting your *.so's to be found, that worked great for me using AS 0.8.11! What formerly I had under `libs/armeabi-v7a/` in Eclipse was picked up under `src/main/jniLibs/armeabi/` – qix Oct 02 '14 at 19:04
  • 2
    I tried this with Android Studio 1.0.1 and gradle version 2.2.1 but it did not work. Any clues? – Neo Jan 07 '15 at 15:36
  • Refer my answer here : http://stackoverflow.com/questions/27532062/android-studio-include-pre-compiled-static-library-using-ndk/28430178#28430178 – Vasanth Feb 10 '15 at 11:17
  • It feels like Gradle is very poorly documented even though it has tons of doc pages. – milosmns Oct 16 '15 at 09:41
  • Check out @Riyaz Mohammed's comment on one of the answers below. It's a more recent and correct/easy solution! – Amber Oct 28 '15 at 19:12