如何在Android Studio中包含* .so库?


123

我读了很多关于如何向Android Studio添加* .so库的线程,但是它们都不起作用,尤其是在文本方面:这不适用于较新的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.+

模组/应用程式:属性:

编译SDK版本19生成工具版本19.1.0

依存关系:

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

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

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

我已经预编译了* .so文件,并且在演示应用程序中它们正在工作。我必须更改应用程序的源代码,因此需要使用相同的* .so文件进行重建。


从android项目外部的目录中添加一个.so文件:stackoverflow.com/questions/50713933/…–
user1506104

Answers:


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

如何创建此自定义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)
}

在相关问题中也可以找到相同的答案:在Android Studio中的APK中包含.so库


6
Compile任务已被弃用。使用JavaCompile替代(从相关答案)
谢尔盖·

我应该把任务放在哪里?
masoud vali

2
请首先尝试jniLibs文件夹解决方案。此任务应放入您的app / library gradle.build文件中。
nenick


在此还看到(列出了不同架构的子文件夹):cumulations.com/blogs/9/...
NorbertM

222

在Android Studio 1.0.2中添加.so库

  1. 在“ src / main /”内部创建文件夹“ jniLibs”
  2. 将所有.so库放入“ src / main / jniLibs”文件夹中
  3. 文件夹结构如下
    所示:| --app:
    |-| --src:
    |-|-| --main
    |-|-|-|| --jniLibs
    |-|-|- |-| --armeabi
    |-|-|- |-| ------。so 文件
    |-|-|-||-| --x86
    |-|- |-|-||-|-。so文件
  4. 无需额外的代码,只需同步您的项目并运行您的应用程序即可。

    参考
    https://github.com/commonsguy/sqlcipher-gradle/tree/master/src/main

6
这不适用于Studio的2015年6月16日测试版
bugfixr

6
这是正确的答案,可以在Android Studio 1.2.2中使用。检查并验证。
Akhil Jain

3
使用Android Studio 1.3.1。
Jaime Hablutzel

3
为我工作。在Android Studio 2.1.2上:)
ShujatAli 2016年

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/

编辑必须是jniLibs.srcDirs,而不是jni.srcDirs-编辑了代码。该目录可以是指向项目目录外部的[相对]路径。


1
解决方案2对我不起作用。我收到一个构建错误:“在源集“ main”上找不到属性“ jni”。”
格雷格·布朗

秘密是“需要在与“ Java”或“ Assets”文件夹相同的文件夹中创建“ jniLibs”文件夹。谢谢!
塞拉芬

方法1允许我正确地进行编译,第二个方法在AS中创建了一个“ cpp”文件夹,并给了我关于缺少C ++编译器的错误
fillobotto

解决方案2必须使用jniLibs.srcDirs,而不是jni.srcDirs来指定本机库的位置(路径可以是相对的或绝对的,甚至可以指向项目目录之外)。
astraujums

对于方案二,你需要把source Sets {下代码android {
yennster

26

* .so库在Android Studio中

您必须在android Studio项目的main内部生成jniLibs文件夹,并将所有.so文件放入其中。您还可以将此行集成到build.gradle中

编译fileTree(dir:'libs',包括:['. jar','. so'])

完美地工作

| --app:

|-| --src:

|-|-|-主要

|-|-||-| --jniLibs

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

|-|-||-|-|-|-。so文件

这是项目结构。


4
编译fileTree(dir:'libs',include:['.jar','。so'])中添加.so解决了我的问题。thnx
BST Kaal 2016年

如果仍然在以下解决方案之后,请尝试android ndk r10e
Vineet Setia

12

这是我的build.gradle文件,请注意这一行

jniLibs.srcDirs = ['libs']

这会将libs的* .so文件包含到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

Android NDK官方hello-libsCMake示例

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)
  • app / 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 only target ARM

示例git跟踪了预构建的共享库,但它也包含实际构建它们的构建系统:https : //github.com/googlesamples/android-ndk/tree/840858984e1bb8a7fab37c1b7c571efbe7d6eb75/hello-libs/gen-libs


2

要使用本机库(so文件),您需要在“ 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

我已经使用打包在jar文件中的外部本机lib依赖项解决了类似的问题。有时将这些体系结构的依赖库一起打包在一个jar中,有时将它们拆分成几个jar文件。所以我写了一些buildscript来扫描jar依赖库中的本机libs并将它们分类到正确的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 /文件夹中。对于其他依赖性,我使用了等级依赖性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.