Как включить библиотеку * .so в Android Studio?


123

Я прочитал много тем, как добавить библиотеку * .so в Android Studio, но ни один из них не работает, особенно когда дело доходит до текста: это не работает с более новым xxx (Android Studio, gradle, ...)

Можем ли мы начать сначала, пожалуйста. Я получил:

Android Studio 0.6.0

Из структуры проекта я вижу:

Расположение SDK:

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

Проект:

Gradle version 1.10
Android Plugin Version 0.11.+

Модули / приложение: Свойства:

Compile Sdk Version 19 Инструменты сборки версии 19.1.0

зависимости:

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

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

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

Я предварительно скомпилировал файлы * .so, и в демонстрационном приложении они работают. Мне нужно изменить исходный код приложения, поэтому мне нужно перестроить с теми же файлами * .so.


добавить файл .so из каталога вне проекта Android: stackoverflow.com/questions/50713933/…
user1506104

Проверьте ответ здесь: stackoverflow.com/a/54977264/8034839
shizhen

Ответы:


108

Текущее решение

Создайте папку project/app/src/main/jniLibs, а затем поместите свои *.soфайлы в их папки abi в этом месте. Например,

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

Устаревшее решение

Добавьте оба фрагмента кода в файл gradle.build вашего модуля в качестве зависимости:

compile fileTree(dir: "$buildDir/native-libs", include: 'native-libs.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)
}

Тот же ответ также можно найти в связанном вопросе: Включить библиотеку .so в apk в студии Android


6
Compileзадача устарела. Использовать JavaCompileвместо (из связанных ответов)
Сергей

куда мне ставить задачи?
Масуд Вали

2
Сначала попробуйте решение для папки jniLibs. Эти задачи нужно поместить в файл приложения / библиотеки gradle.build.
nenick


см. также здесь (перечислены различные подпапки архитектуры): cumulations.com/blogs/9/…
NorbertM

223

Добавление библиотеки .so в Android Studio 1.0.2

  1. Создайте папку "jniLibs" внутри "src / main /"
  2. Поместите все свои библиотеки .so в папку "src / main / jniLibs"
  3. Структура папки выглядит так:
    | --app:
    | - | --src:
    | - | - | --main
    | - | - | - | --jniLibs
    | - | - | - | - | --armeabi
    | - | - | - | - | - | -. Так Файлы
    | - | - | - | - | --x86
    | - | - | - | - | - | -. so Файлы
  4. Никакого дополнительного кода не требуется, просто синхронизируйте ваш проект и запустите приложение.

    Ссылка
    https://github.com/commonsguy/sqlcipher-gradle/tree/master/src/main

6
Это не работает с бета-версией Studio от 16 июня 2015 г.
bugfixr

6
это правильный ответ, работающий в Android Studio 1.2.2. проверено и проверено.
Akhil Jain

3
Работа с Android Studio 1.3.1.
Хайме Хаблутцель

3
Работал у меня thnx. на android studio 2.1.2 :)
ShujatAli

3
работает с Android Studio 3.2.1, отлично! Все еще нигде не документировано! ???
NorbertM

29

Решение 1. Создание папки JniLibs

Создайте папку с именем «jniLibs» в своем приложении и папки, содержащие ваши * .so внутри. Папку «jniLibs» необходимо создать в той же папке, что и папки «Java» или «Assets».

Решение 2. Модификация файла build.gradle

Если вы не хотите создавать новую папку и хранить свои файлы * .so в папке libs, это возможно!

В этом случае просто добавьте свои файлы * .so в папку libs (пожалуйста, соблюдайте ту же архитектуру, что и решение 1: например, libs / armeabi / .so) и измените файл build.gradle вашего приложения, чтобы добавить исходный каталог файлов jniLibs.

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

У вас будет больше объяснений со скриншотами, которые помогут вам здесь (шаг 6):

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

EDIT Это должно было быть jniLibs.srcDirs, а не jni.srcDirs - редактировать код. Каталог может быть [относительным] путем, указывающим за пределы каталога проекта.


1
Решение 2 у меня не работает. Я получаю сообщение об ошибке сборки: «Не удалось найти свойство 'jni' в исходном наборе 'main'».
Грег Браун

Секрет был в том, что папку «jniLibs» нужно создать в той же папке, что и папки «Java» или «Assets». Спасибо!
Seraphim's

Метод 1 позволил мне скомпилировать правильно, второй - создал папку «cpp» в AS и выдал мне ошибку об отсутствии компилятора C ++
fillobotto

Решение 2 должно было использовать jniLibs.srcDirs, а не jni.srcDirs, чтобы можно было указать расположение собственных библиотек (путь может быть относительным или абсолютным и может указывать даже за пределы каталога проекта).
astraujums

Для Решения 2 вам нужно разместить source Sets {код в android {разделе
yennster

26

* .so библиотека в Android Studio

Вам нужно создать папку jniLibs внутри main в проектах Android Studio и поместить все ваши файлы .so внутрь. Вы также можете интегрировать эту строку в build.gradle

скомпилировать fileTree (dir: 'libs', include: [' .jar', ' .so'])

Это работает отлично

| --App:

| - | --src:

| - | - | --main

| - | - | - | --jniLibs

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

| - | - | - | - | - | -. so Файлы

Это структура проекта.


4
Добавление .so в компиляцию fileTree (dir: 'libs', include: ['.jar', '. So ']) решило мою проблему с prb. thnx
BST Kaal

Если решение ниже не устранено, попробуйте android ndk r10e
Vineet

12

Это мой файл build.gradle, обратите внимание на строку

jniLibs.srcDirs = ['libs']

Это будет включать файл * .so libs в 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')
}

5

Официальный hello-libsпример CMake Android NDK

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

Просто работал у меня на хосте Ubuntu 17.10, Android Studio 3, Android SDK 26, поэтому я настоятельно рекомендую вам основывать свой проект на нем.

Общая библиотека называется libgperf, ключевые части кода:

  • 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)
  • приложение / build.gradle :

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

    Затем, если вы посмотрите /data/appна устройство, оно libgperf.soтоже будет там.

  • в коде C ++ используйте: #include <gperf.h>

  • расположение заголовка: hello-libs/distribution/gperf/include/gperf.h

  • расположение библиотеки: distribution/gperf/lib/arm64-v8a/libgperf.so

  • Если вы поддерживаете только некоторые архитектуры, см .: Gradle Build NDK таргетинг только на ARM

Пример git отслеживает предварительно созданные общие библиотеки, но он также содержит систему сборки для их фактического создания: https://github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs/gen-libs


2

Для использования native-библиотеки (so files) вам необходимо добавить несколько кодов в файл "build.gradle".

Этот код предназначен для очистки каталога «armeabi» и копирования файлов «so» в «armeabi» во время «чистого проекта».

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

Я получил ссылку снизу. https://gist.github.com/pocmo/6461138


2

Я решил аналогичную проблему, используя внешние собственные зависимости lib, которые упакованы внутри файлов jar. Иногда эти зависящие от архитектуры библиотеки упаковываются целиком внутри одного jar-файла, иногда они разделяются на несколько jar-файлов. поэтому я написал скрипт сборки для сканирования зависимостей jar для нативных библиотек и сортировки их по нужным папкам android lib. Кроме того, это также обеспечивает способ загрузки зависимостей, которых нет в репозиториях maven, что в настоящее время полезно для работы JNA на android, поскольку не все собственные jar-файлы публикуются в общедоступных репозиториях 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'])

0

Я пробовал решения в приведенных выше ответах, но ни один из них не помог мне. У меня была библиотека с файлами .so, .dll и .jar. В конце концов, я сделал это, подробности можно увидеть здесь: https://stackoverflow.com/a/54976458/7392868

Я копирую вставленные файлы .so в папку с именем jniLibs и вставляю их в папку app / src / main /. Для других зависимостей я использовал зависимости классов.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.