Comment inclure la bibliothèque * .so dans Android Studio?

123

J'ai lu de nombreux threads sur la façon d'ajouter une bibliothèque * .so à Android Studio, mais aucun d'entre eux ne fonctionne, surtout en ce qui concerne le point de texte: cela ne fonctionne pas avec le nouveau xxx (Android Studio, gradle, ...)

Pouvons-nous prendre un nouveau départ s'il vous plaît. J'ai eu:

Android Studio 0.6.0

De la structure du projet, je vois:

Emplacement du SDK:

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

Projet:

Gradle version 1.10
Android Plugin Version 0.11.+

Modules / appli: Propriétés:

Compiler la version 19 des outils de compilation de la version 19.1.0 de Sdk

Dépendances:

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

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

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

J'ai les fichiers * .so pré-compilés et sur l'application de démonstration, ils fonctionnent. Je dois changer le code source de l'application, donc je dois reconstruire avec les mêmes fichiers * .so.

Ronald Wiplinger
la source
ajouter un fichier .so à partir du répertoire en dehors du projet Android: stackoverflow.com/questions/50713933/…
user1506104
Vérifiez la réponse ici: stackoverflow.com/a/54977264/8034839
shizhen

Réponses:

108

Solution actuelle

Créez le dossier project/app/src/main/jniLibs, puis placez vos *.sofichiers dans leurs dossiers abi à cet emplacement. Par exemple,

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

Solution obsolète

Ajoutez les deux extraits de code dans votre fichier gradle.build de module en tant que dépendance:

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

Comment créer ce pot personnalisé:

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 même réponse peut également être trouvée dans la question connexe: Inclure la bibliothèque .so dans apk dans android studio

nenick
la source
6
Compilela tâche est obsolète. Utiliser à la JavaCompileplace (à partir des réponses connexes)
Sergii
où dois-je mettre les tâches?
masoud vali
2
Veuillez d'abord essayer la solution de dossier jniLibs. Ces tâches doivent être placées dans le fichier gradle.build de votre application / bibliothèque.
nenick le
Référence pour le jniLibschemin du répertoire dans Gradle Plugin User Guide - Project Structure
Eido95
voir aussi ici (liste les différents sous-dossiers d'architecture): cumulations.com/blogs/9/...
NorbertM
222

Ajout de la bibliothèque .so dans Android Studio 1.0.2

  1. Créer le dossier "jniLibs" dans "src / main /"
  2. Mettez toutes vos bibliothèques .so dans le dossier "src / main / jniLibs"
  3. La structure des dossiers ressemble à,
    | --app:
    | - | --src:
    | - | - | --main
    | - | - | - | --jniLibs
    | - | - | - | - | --armeabi
    | - | - | - | - | - | -. so Fichiers
    | - | - | - | - | --x86
    | - | - | - | - | - | -. so Fichiers
  4. Aucun code supplémentaire ne nécessite simplement de synchroniser votre projet et d'exécuter votre application.

    Référence
    https://github.com/commonsguy/sqlcipher-gradle/tree/master/src/main
Vasanth
la source
6
Cela ne fonctionne pas avec la version bêta du 16 juin 2015 de Studio
bugfixr
6
c'est la bonne réponse, fonctionnant dans Android Studio 1.2.2. vérifié et vérifié.
Akhil Jain
3
Travailler avec Android Studio 1.3.1.
Jaime Hablutzel
3
A travaillé pour moi thnx. sur android studio 2.1.2 :)
ShujatAli
3
fonctionne avec Android Studio 3.2.1, c'est parfait! Toujours pas documenté nulle part! ???
NorbertM
29

Solution 1: Création d'un dossier JniLibs

Créez un dossier appelé «jniLibs» dans votre application et les dossiers contenant votre * .so à l'intérieur. Le dossier «jniLibs» doit être créé dans le même dossier que vos dossiers «Java» ou «Assets».

Solution 2: Modification du fichier build.gradle

Si vous ne voulez pas créer un nouveau dossier et conserver vos fichiers * .so dans le dossier libs, c'est possible!

Dans ce cas, ajoutez simplement vos fichiers * .so dans le dossier libs (veuillez respecter la même architecture que la solution 1: libs / armeabi / .so par exemple) et modifiez le fichier build.gradle de votre application pour ajouter le répertoire source des jniLibs.

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

Vous aurez plus d'explications, avec des captures d'écran pour vous aider ici (étape 6):

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

EDIT Cela devait être jniLibs.srcDirs, pas jni.srcDirs - édité le code. Le répertoire peut être un chemin [relatif] qui pointe en dehors du répertoire du projet.

GuillaumeAgis
la source
1
La solution 2 ne fonctionne pas pour moi. J'obtiens une erreur de construction: "Impossible de trouver la propriété 'jni' sur l'ensemble de sources 'main'."
Greg Brown
Le secret était «Le dossier« jniLibs »doit être créé dans le même dossier que vos dossiers« Java »ou« Assets ».». Merci!
Seraphim's
La méthode 1 m'a permis de compiler correctement, la deuxième a créé un dossier "cpp" dans AS et m'a donné une erreur sur le compilateur C ++ manquant
fillobotto
La solution 2 a dû utiliser jniLibs.srcDirs, pas jni.srcDirs pour permettre de spécifier l'emplacement des bibliothèques natives (le chemin peut être relatif ou absolu et peut même pointer en dehors du répertoire du projet).
astraujums
Pour la solution 2, vous devez placer le source Sets {code sous la android {section
yennster
26

* bibliothèque .so dans Android Studio

Vous devez générer le dossier jniLibs dans main dans les projets Android Studio et y mettre tous vos fichiers .so. Vous pouvez également intégrer cette ligne dans build.gradle

compiler fileTree (dir: 'libs', inclure: [' .jar', ' .so'])

Ça marche parfaitement

| --app:

| - | --src:

| - | - | --main

| - | - | - | --jniLibs

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

| - | - | - | - | - | -. so Fichiers

C'est la structure du projet.

Ramkailash
la source
4
L'ajout de .so dans compile fileTree (dir: 'libs', include: ['.jar', '. So']) a résolu mon prb. thnx
BST Kaal
Si c'est toujours après la solution ci-dessous, essayez android ndk r10e
Vineet Setia
12

Ceci est mon fichier build.gradle, veuillez noter la ligne

jniLibs.srcDirs = ['libs']

Cela inclura le fichier * .so de libs dans 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')
}
Novembre onze
la source
5

hello-libsExemple officiel de CMake pour Android NDK

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

Je viens de travailler pour moi sur l'hôte Ubuntu 17.10, Android Studio 3, Android SDK 26, donc je vous recommande fortement de baser votre projet dessus.

La bibliothèque partagée est appelée libgperf, les parties du code clé sont:

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

    Ensuite, si vous regardez sous /data/appl'appareil, il libgperf.sosera également là.

  • sur le code C ++, utilisez: #include <gperf.h>

  • emplacement de l'en-tête: hello-libs/distribution/gperf/include/gperf.h

  • emplacement de la bibliothèque: distribution/gperf/lib/arm64-v8a/libgperf.so

  • Si vous ne prenez en charge que certaines architectures, voir: Gradle Build NDK target only ARM

L'exemple git suit les bibliothèques partagées prédéfinies, mais il contient également le système de construction pour les construire également: https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs/gen-libs

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

Pour utiliser la bibliothèque native (donc les fichiers) Vous devez ajouter des codes dans le fichier "build.gradle".

Ce code sert à nettoyer le répertoire «armeabi» et à copier les fichiers «so» dans «armeabi» tout en «nettoyant le projet».

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

J'ai été référé par le bas. https://gist.github.com/pocmo/6461138

jolie angela
la source
2

J'ai résolu un problème similaire en utilisant des dépendances de lib natives externes qui sont emballées à l'intérieur de fichiers jar. Parfois, ces bibliothèques dépendantes de l'architecture sont regroupées dans un même fichier jar, parfois elles sont divisées en plusieurs fichiers jar. J'ai donc écrit un buildscript pour analyser les dépendances jar pour les bibliothèques natives et les trier dans les bons dossiers de lib android. De plus, cela fournit également un moyen de télécharger des dépendances qui ne se trouvent pas dans les dépôts maven, ce qui est actuellement utile pour faire fonctionner JNA sur Android car tous les jars natifs ne sont pas publiés dans des dépôts maven publics.

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
la source
0

J'ai essayé les solutions dans les réponses ci-dessus mais aucune n'a fonctionné pour moi. J'avais une bibliothèque avec des fichiers .so, .dll et .jar. À la fin, j'ai fait cela, vous pouvez voir les détails ici: https://stackoverflow.com/a/54976458/7392868

J'ai copié les fichiers .so dans un dossier nommé jniLibs et les ai collés dans le dossier app / src / main /. Pour les autres dépendances, j'ai utilisé les dépendances de grade.

Muhammad Ali
la source