¿Cómo incluir la biblioteca * .so en Android Studio?

123

Leí muchos hilos sobre cómo agregar una biblioteca * .so a Android Studio, pero ninguno de ellos funciona, especialmente cuando se trata del punto de texto: esto no funciona con el nuevo xxx (Android Studio, gradle, ...)

¿Podemos empezar de nuevo, por favor? Tengo:

Android Studio 0.6.0

De la estructura del proyecto veo:

Ubicación del SDK:

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

Proyecto:

Gradle version 1.10
Android Plugin Version 0.11.+

Módulos / aplicación: Propiedades:

Compile SDK versión 19 Herramientas de compilación versión 19.1.0

Dependencias:

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

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

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

Obtuve los archivos * .so precompilados y en la aplicación de demostración están funcionando. Tengo que cambiar el código fuente de la aplicación, así que necesito reconstruir con los mismos archivos * .so.

Ronald Wiplinger
fuente
agregue un archivo .so desde el directorio fuera del proyecto de Android: stackoverflow.com/questions/50713933/…
user1506104
Compruebe la respuesta aquí: stackoverflow.com/a/54977264/8034839
shizhen

Respuestas:

108

Solución actual

Cree la carpeta project/app/src/main/jniLibsy luego coloque sus *.soarchivos dentro de sus carpetas abi en esa ubicación. P.ej,

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

Solución obsoleta

Agregue ambos fragmentos de código en el archivo gradle.build de su módulo como una dependencia:

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

Cómo crear este jar personalizado:

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)
}

La misma respuesta también se puede encontrar en la pregunta relacionada: Incluir la biblioteca .so en apk en el estudio de Android

nenick
fuente
66
CompileLa tarea ha quedado en desuso. Usar en su JavaCompilelugar (de las respuestas relacionadas)
Sergii
¿Dónde debo poner las tareas?
masoud vali
2
Intente primero la solución de carpeta jniLibs. Estas tareas deben colocarse en el archivo gradle.build de su aplicación / biblioteca.
nenick
Referencia para la jniLibsruta del directorio en la Guía del usuario de Gradle Plugin - Estructura del proyecto
Eido95
vea también aquí (enumera las diferentes subcarpetas de arquitectura): cumulations.com/blogs/9/…
NorbertM
222

Agregar biblioteca .so en Android Studio 1.0.2

  1. Crear carpeta "jniLibs" dentro de "src / main /"
  2. Coloque todas sus bibliotecas .so dentro de la carpeta "src / main / jniLibs"
  3. La estructura de la carpeta tiene el siguiente aspecto:
    | --app:
    | - | --src:
    | - | - | --main
    | - | - | - | --jniLibs
    | - | - | - | - | --armeabi
    | - | - | - | - | - | -. so Archivos
    | - | - | - | - | --x86
    | - | - | - | - | - | -. so Archivos
  4. Ningún código adicional requiere simplemente sincronizar su proyecto y ejecutar su aplicación.

    Referencia
    https://github.com/commonsguy/sqlcipher-gradle/tree/master/src/main
Vasanth
fuente
66
Esto no funciona con la versión beta de Studio del 16 de junio de 2015
corrección de errores
66
Esta es la respuesta correcta, trabajando en Android Studio 1.2.2. comprobado y verificado.
Akhil Jain
3
Trabajando con Android Studio 1.3.1.
Jaime Hablutzel
3
Trabajó para mí gracias. en Android Studio 2.1.2 :)
ShujatAli
3
funciona con Android Studio 3.2.1, ¡genial! ¿Todavía no está documentado en ningún lado?
NorbertM
29

Solución 1: creación de una carpeta JniLibs

Cree una carpeta llamada "jniLibs" en su aplicación y las carpetas que contienen su * .so dentro. La carpeta "jniLibs" debe crearse en la misma carpeta que las carpetas "Java" o "Activos".

Solución 2: modificación del archivo build.gradle

Si no desea crear una nueva carpeta y mantener sus archivos * .so en la carpeta libs, ¡es posible!

En ese caso, solo agregue sus archivos * .so en la carpeta libs (respete la misma arquitectura que la solución 1: libs / armeabi / .so por ejemplo) y modifique el archivo build.gradle de su aplicación para agregar el directorio fuente de los jniLibs.

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

Tendrás más explicaciones, con capturas de pantalla para ayudarte aquí (Paso 6):

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

EDITAR Tenía que ser jniLibs.srcDirs, no jni.srcDirs, editó el código. El directorio puede ser una ruta [relativa] que apunte fuera del directorio del proyecto.

GuillaumeAgis
fuente
1
La solución 2 no funciona para mí. Aparece un error de compilación: "No se pudo encontrar la propiedad 'jni' en el conjunto de fuentes 'main'".
Greg Brown
El secreto era 'La carpeta "jniLibs" debe crearse en la misma carpeta que las carpetas "Java" o "Activos". ¡Gracias!
Seraphim's
El método 1 me permitió compilar correctamente, el segundo creó una carpeta "cpp" en AS y me dio un error sobre la falta del compilador de C ++
fillobotto
La solución 2 tenía que usar jniLibs.srcDirs, no jni.srcDirs para permitir especificar la ubicación de las bibliotecas nativas (la ruta puede ser relativa o absoluta y puede apuntar incluso fuera del directorio del proyecto).
astraujums
Para la Solución 2, debe colocar el source Sets {código debajo de la android {sección
yennster
26

* .so biblioteca en Android Studio

Tienes que generar la carpeta jniLibs dentro de main en proyectos de Android Studio y poner todos tus archivos .so dentro. También puede integrar esta línea en build.gradle

compilar fileTree (dir: 'libs', incluir: [' .jar', ' .so'])

Funciona perfectamente

| --app:

| - | --src:

| - | - | --principal

| - | - | - | --jniLibs

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

| - | - | - | - | - | -. so Archivos

Esta es la estructura del proyecto.

Ramkailash
fuente
44
Agregar .so en compilar fileTree (dir: 'libs', incluir: ['.jar', '. So ']) resolvió mi problema. thnx
BST Kaal
Si todavía está después de la solución a continuación, intente Android ndk r10e
Vineet Setia
12

Este es mi archivo build.gradle, tenga en cuenta la línea

jniLibs.srcDirs = ['libs']

Esto incluirá el archivo * .so de libs para 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')
}
Noviembre once
fuente
5

hello-libsEjemplo de CMake oficial de Android NDK

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

Simplemente funcionó para mí en el host Ubuntu 17.10, Android Studio 3, Android SDK 26, por lo que le recomiendo que base su proyecto en él.

Se llama a la biblioteca compartida libgperf, las partes clave del código son:

  • 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']

    Luego, si miras debajo /data/appdel dispositivo, libgperf.sotambién estará allí.

  • en código C ++, use: #include <gperf.h>

  • ubicación del encabezado: hello-libs/distribution/gperf/include/gperf.h

  • ubicación lib: distribution/gperf/lib/arm64-v8a/libgperf.so

  • Si solo admite algunas arquitecturas, consulte: Gradle Build NDK solo objetivo ARM

El ejemplo git rastrea las bibliotecas compartidas preconstruidas, pero también contiene el sistema de compilación para compilarlas realmente: https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs/gen-libs

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
2

Para usar una biblioteca nativa (por lo tanto, archivos) Debe agregar algunos códigos en el archivo "build.gradle".

Este código es para limpiar el directorio "armeabi" y copiar archivos 'so' en "armeabi" mientras se 'limpia el proyecto'.

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

Me han referido a continuación. https://gist.github.com/pocmo/6461138

linda angela
fuente
2

He resuelto un problema similar usando dependencias de lib nativas externas que se empaquetan dentro de los archivos jar. A veces, estas bibliotecas dependientes de la arquitectura se empaquetan en un solo contenedor, a veces se dividen en varios archivos jar. así que escribí un buildscript para escanear las dependencias jar de las bibliotecas nativas y ordenarlas en las carpetas de lib de Android correctas. Además, esto también proporciona una forma de descargar dependencias que no se encuentran en repositorios de Maven, que actualmente es útil para que JNA funcione en Android porque no todos los tarros nativos se publican en repositorios públicos de Maven.

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'])
ene
fuente
0

Probé las soluciones en las respuestas anteriores, pero ninguna funcionó para mí. Tenía una biblioteca con archivos .so, .dll y .jar. Al final hice esto, puedes ver los detalles aquí: https://stackoverflow.com/a/54976458/7392868

Copié los archivos .so pegados en una carpeta llamada jniLibs y los pegué dentro de la carpeta app / src / main /. Para otras dependencias utilicé las dependencias de grado.

Muhammad Ali
fuente