How to include *.so library in Android Studio?
Asked Answered
B

9

163

I read many threads how to add a *.so library to Android Studio, but none of them works, especially when it comes to the point of text: This does not work with the newer xxx (Android Studio, gradle, ...)

Can we make a fresh start please. I got:

Android Studio 0.6.0

From Project Structure I see:

SDK Location:

/usr/share/android-studio/data/sdk
/usr/lib/jvm/default-java

Project:

Gradle version 1.10
Android Plugin Version 0.11.+

Modules/app: Properties:

Compile Sdk Version 19 Build Tools Version 19.1.0

Dependencies:

{dir=libs, include=[*.jar]} Compile

{dir=libs, include=[*.so]}  Provided

m com.android.support: appcompat -v7:19.+   Compile

I got the *.so files pre-compiled and at the demo app they are working. I have to change the source code of the app, so I need to rebuild with the same *.so files.

Boathouse answered 23/6, 2014 at 2:27 Comment(2)
add a .so file from directory outside android project: #50714433Imago
Check answer here: https://mcmap.net/q/49361/-how-can-i-set-up-a-simple-gradle-project-that-uses-sqlite4javaGwennie
A
138

Current Solution

Create the folder project/app/src/main/jniLibs, and then put your *.so files within their abi folders in that location. E.g.,

project/
├──libs/
|  └── *.jar       <-- if your library has jar files, they go here
├──src/
   └── main/
       ├── AndroidManifest.xml
       ├── java/
       └── jniLibs/ 
           ├── arm64-v8a/                       <-- ARM 64bit
           │   └── yourlib.so
           ├── armeabi-v7a/                     <-- ARM 32bit
           │   └── yourlib.so
           └── x86/                             <-- Intel 32bit
               └── yourlib.so

Deprecated solution

Add both code snippets in your module gradle.build file as a dependency:

compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar')

How to create this custom jar:

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

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

Same answer can also be found in related question: Include .so library in apk in android studio

Antecedents answered 23/6, 2014 at 7:15 Comment(10)
Compile task has been deprecated. Use JavaCompile instead (from related answers)Pubis
where should i put the tasks?Eon
Please try first the jniLibs folder solution. This tasks should be put into your app/library gradle.build file.Antecedents
Reference for the jniLibs directory path at Gradle Plugin User Guide - Project StructurePhonoscope
see also here (lists the different architecture sub-folders): cumulations.com/blogs/9/…Metalinguistic
My output is a static file, i have tried but its not package into the apkSubteen
How to call Native library method in ActivityKirt
Hi I want to also know where can I add my includes folder for my header files as I'm writing a C++ native codeSyllogism
It's very strange that If my app named libxxx.so, it can copy, but xxx.so, not copied.Asserted
Outdated now. Please use the answer by @Claud instead: https://mcmap.net/q/49033/-how-to-include-so-library-in-android-studioEanore
C
262

Adding .so Library in Android Studio 1.0.2

  1. Create Folder "jniLibs" inside "src/main/"
  2. Put all your .so libraries inside "src/main/jniLibs" folder
  3. Folder structure looks like,
    |--app:
    |--|--src:
    |--|--|--main
    |--|--|--|--jniLibs
    |--|--|--|--|--armeabi
    |--|--|--|--|--|--.so Files
    |--|--|--|--|--x86
    |--|--|--|--|--|--.so Files
  4. No extra code requires just sync your project and run your application.

    Reference
    https://github.com/commonsguy/sqlcipher-gradle/tree/master/src/main
Claud answered 10/2, 2015 at 11:18 Comment(20)
Thank you. I found this answer to be the, by far, easiest way of solving the issue while still keeping the gradle config white-noise to a minimum.Annual
Using this method but I have a xxx.so.9 file and it is not copied. Getting error about that file is not found. How to make it copied?Maganmagana
This isn't working with the June 16, 2015 beta version of StudioSalim
this is correct answer, working in Android Studio 1.2.2. checked and verified.Time
Working with Android Studio 1.3.1.Edgewise
Worked for me, thanx! with gradle-experimentalSubtractive
Worked for me thnx . on android studio 2.1.2 :)Cissie
What about Android Studio 2.2? I have 7 .so files for 7 archs. However how can I include them in my project.Distillate
Worked for me on Android Studio 2.2 October 2016. Thanks ☺Tie
Worked on Android Studio 2.2.3. Thanks !Quantity
isn't working for me, getting java.lang.UnsatisfiedLinkError "couldn't find "libFPEComponent.so"Bea
What about x86_64. jniLibs/x86_64 isn't working for me :(Promycelium
Still correct answer. @VikasPandey you load up FPECComponent, not lib + .so nameJohannesburg
works with Android Studio 3.2.1, great! Still not documented anywhere !???Metalinguistic
@Vasantha LInk not validSerpigo
Worked on Android Studio 4.1.1Hughey
Worked on Android Studio 4.1.3Shaylyn
@Metalinguistic documented here developer.android.com/studio/projects/… SEVEN YEARS LATER. ;-OAmadoamador
also you should add ndk { abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a' }Brescia
Its working well in Debug mode but never works in release modeCame
A
138

Current Solution

Create the folder project/app/src/main/jniLibs, and then put your *.so files within their abi folders in that location. E.g.,

project/
├──libs/
|  └── *.jar       <-- if your library has jar files, they go here
├──src/
   └── main/
       ├── AndroidManifest.xml
       ├── java/
       └── jniLibs/ 
           ├── arm64-v8a/                       <-- ARM 64bit
           │   └── yourlib.so
           ├── armeabi-v7a/                     <-- ARM 32bit
           │   └── yourlib.so
           └── x86/                             <-- Intel 32bit
               └── yourlib.so

Deprecated solution

Add both code snippets in your module gradle.build file as a dependency:

compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.jar')

How to create this custom jar:

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

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

Same answer can also be found in related question: Include .so library in apk in android studio

Antecedents answered 23/6, 2014 at 7:15 Comment(10)
Compile task has been deprecated. Use JavaCompile instead (from related answers)Pubis
where should i put the tasks?Eon
Please try first the jniLibs folder solution. This tasks should be put into your app/library gradle.build file.Antecedents
Reference for the jniLibs directory path at Gradle Plugin User Guide - Project StructurePhonoscope
see also here (lists the different architecture sub-folders): cumulations.com/blogs/9/…Metalinguistic
My output is a static file, i have tried but its not package into the apkSubteen
How to call Native library method in ActivityKirt
Hi I want to also know where can I add my includes folder for my header files as I'm writing a C++ native codeSyllogism
It's very strange that If my app named libxxx.so, it can copy, but xxx.so, not copied.Asserted
Outdated now. Please use the answer by @Claud instead: https://mcmap.net/q/49033/-how-to-include-so-library-in-android-studioEanore
S
38

Solution 1 : Creation of a JniLibs folder

Create a folder called “jniLibs” into your app and the folders containing your *.so inside. The "jniLibs" folder needs to be created in the same folder as your "Java" or "Assets" folders.

Solution 2 : Modification of the build.gradle file

If you don’t want to create a new folder and keep your *.so files into the libs folder, it is possible !

In that case, just add your *.so files into the libs folder (please respect the same architecture as the solution 1 : libs/armeabi/.so for instance) and modify the build.gradle file of your app to add the source directory of the jniLibs.

sourceSets {
    main {
        jniLibs.srcDirs = ["libs"]
    }
}

You will have more explanations, with screenshots to help you here ( Step 6 ):

http://blog.guillaumeagis.eu/setup-andengine-with-android-studio/

EDIT It had to be jniLibs.srcDirs, not jni.srcDirs - edited the code. The directory can be a [relative] path that points outside of the project directory.

Sclerotic answered 24/3, 2015 at 14:7 Comment(6)
Solution 2 doesn't work for me. I get a build error: "Could not find property 'jni' on source set 'main'."Kirkuk
The secret was 'The "jniLibs" folder needs to be created in the same folder as your "Java" or "Assets" folders.'. Thanks!Caird
Method 1 allowed me to compile correctly, second one created a "cpp" folder in AS and gave me error about missing C++ compilerSpeaker
Solution 2 had to use jniLibs.srcDirs, not jni.srcDirs to allow specifying the location of native libraries (the path can be relative or absolute and can point even outside the project directory).Windhover
For Solution 2 you need to place the source Sets { code under the android { sectionPeroxidase
for me adding 'src/main/jniLibs' to jniLibs.srcDirs is needed, thx!Stamm
M
27

*.so library in Android Studio

You have to generate jniLibs folder inside main in android Studio projects and put your all .so files inside. You can also integrate this line in build.gradle

compile fileTree(dir: 'libs', include: ['.jar','.so'])

It's work perfectly

|--app:

|--|--src:

|--|--|--main

|--|--|--|--jniLibs

|--|--|--|--|--armeabi

|--|--|--|--|--|--.so Files

This is the project structure.

Masterful answered 27/8, 2015 at 7:24 Comment(2)
Adding .so in compile fileTree(dir: 'libs', include: ['.jar','.so']) solved my prb. thnxAffirm
If it is still after below solution, try android ndk r10eAgonist
N
11

This is my build.gradle file, Please note the line

jniLibs.srcDirs = ['libs']

This will include libs's *.so file to apk.

sourceSets {
    main {
        manifest.srcFile 'AndroidManifest.xml'
        java.srcDirs = ['src']
        resources.srcDirs = ['src']
        aidl.srcDirs = ['src']
        renderscript.srcDirs = ['src']
        res.srcDirs = ['res']
        assets.srcDirs = ['assets']
        jniLibs.srcDirs = ['libs']
    }

    // Move the tests to tests/java, tests/res, etc...
    instrumentTest.setRoot('tests')

    // Move the build types to build-types/<type>
    // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
    // This moves them out of them default location under src/<type>/... which would
    // conflict with src/ being used by the main source set.
    // Adding new build types or product flavors should be accompanied
    // by a similar customization.
    debug.setRoot('build-types/debug')
    release.setRoot('build-types/release')
}
Nelson answered 10/12, 2014 at 4:3 Comment(0)
G
7

Android NDK official hello-libs CMake example

https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs

Just worked for me on Ubuntu 17.10 host, Android Studio 3, Android SDK 26, so I strongly recommend that you base your project on it.

The shared library is called libgperf, the key code parts are:

  • hello-libs/app/src/main/cpp/CMakeLists.txt:

    // -L
    add_library(lib_gperf SHARED IMPORTED)
    set_target_properties(lib_gperf PROPERTIES IMPORTED_LOCATION
              ${distribution_DIR}/gperf/lib/${ANDROID_ABI}/libgperf.so)
    
    // -I
    target_include_directories(hello-libs PRIVATE
                               ${distribution_DIR}/gperf/include)
    // -lgperf
    target_link_libraries(hello-libs
                          lib_gperf)
    
  • app/build.gradle:

    android {
        sourceSets {
            main {
                // let gradle pack the shared library into apk
                jniLibs.srcDirs = ['../distribution/gperf/lib']
    

    Then, if you look under /data/app on the device, libgperf.so will be there as well.

  • on C++ code, use: #include <gperf.h>

  • header location: hello-libs/distribution/gperf/include/gperf.h

  • lib location: distribution/gperf/lib/arm64-v8a/libgperf.so

  • If you only support some architectures, see: Gradle Build NDK target only ARM

The example git tracks the prebuilt shared libraries, but it also contains the build system to actually build them as well: https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs/gen-libs

Gravelblind answered 30/11, 2017 at 10:56 Comment(0)
S
4

I have solved a similar problem using external native lib dependencies that are packaged inside of jar files. Sometimes these architecture dependend libraries are packaged alltogether inside one jar, sometimes they are split up into several jar files. so i wrote some buildscript to scan the jar dependencies for native libs and sort them into the correct android lib folders. Additionally this also provides a way to download dependencies that not found in maven repos which is currently usefull to get JNA working on android because not all native jars are published in public maven repos.

android {
    compileSdkVersion 23
    buildToolsVersion '24.0.0'

    lintOptions {
        abortOnError false
    }


    defaultConfig {
        applicationId "myappid"
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 1
        versionName "1.0.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    sourceSets {
        main {
            jniLibs.srcDirs = ["src/main/jniLibs", "$buildDir/native-libs"]
        }
    }
}

def urlFile = { url, name ->
    File file = new File("$buildDir/download/${name}.jar")
    file.parentFile.mkdirs()
    if (!file.exists()) {
        new URL(url).withInputStream { downloadStream ->
            file.withOutputStream { fileOut ->
                fileOut << downloadStream
            }
        }
    }
    files(file.absolutePath)
}
dependencies {
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.3.0'
    compile 'com.android.support:design:23.3.0'
    compile 'net.java.dev.jna:jna:4.2.0'
    compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-arm.jar?raw=true', 'jna-android-arm')
    compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-armv7.jar?raw=true', 'jna-android-armv7')
    compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-aarch64.jar?raw=true', 'jna-android-aarch64')
    compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-x86.jar?raw=true', 'jna-android-x86')
    compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-x86-64.jar?raw=true', 'jna-android-x86_64')
    compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-mips.jar?raw=true', 'jna-android-mips')
    compile urlFile('https://github.com/java-native-access/jna/blob/4.2.2/lib/native/android-mips64.jar?raw=true', 'jna-android-mips64')
}
def safeCopy = { src, dst ->
    File fdst = new File(dst)
    fdst.parentFile.mkdirs()
    fdst.bytes = new File(src).bytes

}

def archFromName = { name ->
    switch (name) {
        case ~/.*android-(x86-64|x86_64|amd64).*/:
            return "x86_64"
        case ~/.*android-(i386|i686|x86).*/:
            return "x86"
        case ~/.*android-(arm64|aarch64).*/:
            return "arm64-v8a"
        case ~/.*android-(armhf|armv7|arm-v7|armeabi-v7).*/:
            return "armeabi-v7a"
        case ~/.*android-(arm).*/:
            return "armeabi"
        case ~/.*android-(mips).*/:
            return "mips"
        case ~/.*android-(mips64).*/:
            return "mips64"
        default:
            return null
    }
}

task extractNatives << {
    project.configurations.compile.each { dep ->
        println "Scanning ${dep.name} for native libs"
        if (!dep.name.endsWith(".jar"))
            return
        zipTree(dep).visit { zDetail ->
            if (!zDetail.name.endsWith(".so"))
                return
            print "\tFound ${zDetail.name}"
            String arch = archFromName(zDetail.toString())
            if(arch != null){
                println " -> $arch"
                safeCopy(zDetail.file.absolutePath,
                        "$buildDir/native-libs/$arch/${zDetail.file.name}")
            } else {
                println " -> No valid arch"
            }
        }
    }
}

preBuild.dependsOn(['extractNatives'])
Stroup answered 4/7, 2016 at 8:59 Comment(0)
B
3

I have android studio 4.1.2 and when I tried to set the ndk path in File -> Project Structure -> Sdk Location it would ask me to download the ndk even though it was already installed, I set the NDK_HOME, ANDROID_NDK_HOME and PATH environmental variables and nothing. The only thing that worked for me was manually setting the ndk version in the local.properties, creating a jniLibs (yes with this exact name) folder with the ABIs and their respective .so files and specifying the abi filters and ndk version in the build.gradle. Hope this saves someone else from a headache.

local.properties

ndk.dir=C\:\\Users\\<user>\\AppData\\Local\\Android\\Sdk\\ndk\\22.0.7026061

build.gradle

plugins {
    id 'com.android.application'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdkVersion 22
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
        ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

    }

    sourceSets {
        main {
            jniLibs.srcDir 'jniLibs'
        }
    }

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

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    ndkVersion '22.0.7026061'
}

...\app\src\main\

enter image description here

Inside the jniLibs folder

enter image description here

Burdett answered 22/3, 2021 at 21:59 Comment(0)
D
1

To use native-library (so files) You need to add some codes in the "build.gradle" file.

This code is for cleaing "armeabi" directory and copying 'so' files into "armeabi" while 'clean project'.

task copyJniLibs(type: Copy) {
    from 'libs/armeabi'
    into 'src/main/jniLibs/armeabi'
}
tasks.withType(JavaCompile) {
    compileTask -> compileTask.dependsOn(copyJniLibs)
}
clean.dependsOn 'cleanCopyJniLibs'

I've been referred from the below. https://gist.github.com/pocmo/6461138

Dynah answered 4/3, 2015 at 7:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.