Como incluir a biblioteca * .so no Android Studio?

123

Eu li muitos tópicos sobre como adicionar uma biblioteca * .so ao Android Studio, mas nenhum deles funciona, especialmente quando se trata do ponto do texto: isso não funciona com o xxx mais recente (Android Studio, gradle, ...)

Podemos começar de novo, por favor. Eu tenho:

Android Studio 0.6.0

Na estrutura do projeto, vejo:

Localização do SDK:

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

Projeto:

Gradle version 1.10
Android Plugin Version 0.11.+

Módulos / aplicativo: Propriedades:

Compile Sdk Versão 19 Versão 19.1.0 das Ferramentas de Construção

Dependências:

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

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

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

Eu tenho os arquivos * .so pré-compilados e no aplicativo demo eles estão trabalhando. Eu tenho que mudar o código fonte do aplicativo, então preciso reconstruir com os mesmos arquivos * .so.

Ronald Wiplinger
fonte
adicione um arquivo .so do diretório fora do projeto android: stackoverflow.com/questions/50713933/…
user1506104:
Verifique resposta aqui: stackoverflow.com/a/54977264/8034839
Shizhen

Respostas:

108

Solução Atual

Crie a pasta project/app/src/main/jniLibse, em seguida, coloque seus *.soarquivos nas pastas abi desse local. Por exemplo,

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

Solução preterida

Adicione os dois trechos de código no arquivo gradle.build do módulo como uma dependência:

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

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

A mesma resposta também pode ser encontrada em perguntas relacionadas: Inclua a biblioteca .so no apk no android studio

nenick
fonte
6
Compiletarefa foi descontinuada. Use em JavaCompilevez disso (a partir de respostas relacionadas)
Sergii 16/05
onde devo colocar as tarefas?
masoud vali
2
Por favor, tente primeiro a solução da pasta jniLibs. Essas tarefas devem ser colocadas no arquivo gradle.build do aplicativo / biblioteca.
Nenick 16/09/16
Referência para o jniLibscaminho do diretório no Guia do Usuário Gradle Plugin - Estrutura do Projeto
Eido95
veja também aqui (lista as diferentes subpastas da arquitetura): cumulations.com/blogs/9/…
NorbertM 14/11/18
222

Adicionando a biblioteca .so no Android Studio 1.0.2

  1. Crie uma pasta "jniLibs" dentro de "src / main /"
  2. Coloque todas as suas bibliotecas .so na pasta "src / main / jniLibs"
  3. A estrutura da pasta é semelhante a
    | |app:
    | - | --src:
    | - | - | --main
    | - | - | - | --jniLibs
    | - | - | - | - | --armeabi
    | - | - | - | - | - | -. so Arquivos
    | - | - | - | - | --x86
    | - | - Arquivos | - | - | - | -. so
  4. Nenhum código extra requer apenas sincronizar seu projeto e executar seu aplicativo.

    Referência
    https://github.com/commonsguy/sqlcipher-gradle/tree/master/src/main
Vasanth
fonte
6
Isto não está funcionando com o 16 de junho de 2015 versão beta do Estúdio
bugfixr
6
esta é a resposta correta, trabalhando no Android Studio 1.2.2. verificado e verificado.
Akhil Jain
3
Trabalhando com o Android Studio 1.3.1.
Jaime Hablutzel
3
Trabalhou para mim thnx. no android studio 2.1.2 :)
ShujatAli
3
funciona com Android Studio 3.2.1, ótimo! Ainda não está documentado em nenhum lugar! ???
NorbertM
29

Solução 1: Criação de uma pasta JniLibs

Crie uma pasta chamada "jniLibs" em seu aplicativo e as pastas que contêm seu * .so dentro. A pasta "jniLibs" precisa ser criada na mesma pasta que as pastas "Java" ou "Ativos".

Solução 2: modificação do arquivo build.gradle

Se você não deseja criar uma nova pasta e manter seus arquivos * .so na pasta libs, é possível!

Nesse caso, basta adicionar seus arquivos * .so à pasta libs (respeite a mesma arquitetura da solução 1: libs / armeabi / .so, por exemplo) e modifique o arquivo build.gradle do seu aplicativo para adicionar o diretório de origem dos jniLibs.

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

Você terá mais explicações, com capturas de tela para ajudá-lo aqui (Etapa 6):

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

EDIT Tinha que ser jniLibs.srcDirs, não jni.srcDirs - editou o código. O diretório pode ser um caminho [relativo] que aponta para fora do diretório do projeto.

GuillaumeAgis
fonte
1
Solução 2 não funciona para mim. Recebo um erro de compilação: "Não foi possível encontrar a propriedade 'jni' no conjunto de fontes 'main'."
Greg Brown
O segredo era 'A pasta "jniLibs" precisa ser criada na mesma pasta que as pastas "Java" ou "Ativos".'. Obrigado!
Serafim
Método 1 permitiu-me para compilar corretamente, segundo criou uma pasta "CPP" na AS e deu-me erro sobre a falta de compilador C ++
fillobotto
A solução 2 teve que usar jniLibs.srcDirs, não jni.srcDirs para permitir a especificação do local das bibliotecas nativas (o caminho pode ser relativo ou absoluto e pode apontar mesmo fora do diretório do projeto).
Astraujums
Para a Solução 2, você precisa colocar o source Sets {código na android {seção
yennster 21/05/19
26

biblioteca * .so no Android Studio

Você precisa gerar a pasta jniLibs dentro do main nos projetos do Android Studio e colocar todos os seus arquivos .so dentro. Você também pode integrar esta linha no build.gradle

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

É funcionar perfeitamente

| --app:

| - | --src:

| - | - | --main

| - | - | - | --jniLibs

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

Arquivos | - | - | - | - | - | -. so

Essa é a estrutura do projeto.

Ramkailash
fonte
4
A adição de .so na compilação fileTree (dir: 'libs', inclui: ['.jar', '. So']) resolveu meu prb. thnx
BST Kaal
Se ainda estiver depois abaixo solução, tente r10e Android NDK
Vineet Setia
12

Este é o meu arquivo build.gradle, observe a linha

jniLibs.srcDirs = ['libs']

Isso incluirá o arquivo * .so da libs no 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')
}
NovemberEleven
fonte
5

hello-libsExemplo oficial do Android NDK CMake

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

Acabei de trabalhar para mim no host Ubuntu 17.10, Android Studio 3, Android SDK 26, por isso recomendo fortemente que você baseie seu projeto nele.

A biblioteca compartilhada é chamada libgperf, as partes do código-chave são:

  • Olá, 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']

    Então, se você olhar embaixo /data/appdo dispositivo, libgperf.sotambém estará lá.

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

  • localização do cabeçalho: hello-libs/distribution/gperf/include/gperf.h

  • localização da lib: distribution/gperf/lib/arm64-v8a/libgperf.so

  • Se você suportar apenas algumas arquiteturas, consulte: Gradle Build NDK target only ARM

O exemplo git rastreia as bibliotecas compartilhadas pré-construídas, mas também contém o sistema de construção para construí-las também: https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs/gen-libs

Ciro Santilli adicionou uma nova foto
fonte
2

Para usar a biblioteca nativa (arquivos)) Você precisa adicionar alguns códigos no arquivo "build.gradle".

Este código serve para limpar o diretório "armeabi" e copiar os arquivos 'so' para o "armeabi" enquanto o 'projeto limpo'.

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

Fui indicado a partir do abaixo. https://gist.github.com/pocmo/6461138

bonita angela
fonte
2

Eu resolvi um problema semelhante usando dependências de lib nativas externas empacotadas dentro de arquivos jar. Às vezes, essas bibliotecas dependentes da arquitetura são empacotadas totalmente em um jar, às vezes são divididas em vários arquivos jar. Então, eu escrevi alguns buildscript para verificar as dependências do jar em busca de bibliotecas nativas e classificá-las nas pastas corretas da biblioteca android. Além disso, isso também fornece uma maneira de baixar dependências que não são encontradas nos repositórios maven, que atualmente são úteis para que o JNA funcione no Android, porque nem todos os jars nativos são publicados em repositórios públicos do 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'])
Jan
fonte
0

Tentei as soluções nas respostas acima, mas nenhuma funcionou para mim. Eu tinha uma biblioteca com arquivos .so, .dll e .jar. No final, eu fiz isso, você pode ver os detalhes aqui: https://stackoverflow.com/a/54976458/7392868

Copiei os arquivos .so em uma pasta chamada jniLibs e colei dentro da pasta app / src / main /. Para outras dependências, usei as dependências de notas.

Muhammad Ali
fonte