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

Posted

技术标签:

【中文标题】如何在 Android Studio 中包含 *.so 库?【英文标题】:How to include *.so library in Android Studio? 【发布时间】:2014-08-13 00:10:12 【问题描述】:

我阅读了很多关于如何将 *.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.+

模块/应用程序: 属性:

编译 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文件:***.com/questions/50713933/… 在这里查看答案:***.com/a/54977264/8034839 【参考方案1】:

在 Android Studio 1.0.2 中添加 .so 库

    在“src/main/”中创建文件夹“jniLibs” 将所有 .so 库放入“src/main/jniLibs”文件夹中 文件夹结构看起来像, |--应用: |--|--src: |--|--|--主要 |--|--|--|--jniLibs |--|--|--|--|--armeabi |--|--|--|--|--|--.so 文件 |--|--|--|--|--x86 |--|--|--|--|--|--.so 文件 无需额外的代码,只需同步您的项目并运行您的应用程序。 参考 https://github.com/commonsguy/sqlcipher-gradle/tree/master/src/main

【讨论】:

这不适用于 2015 年 6 月 16 日的 Studio 测试版 这是正确的答案,在 Android Studio 1.2.2 中工作。检查和验证。 使用 Android Studio 1.3.1。 为我工作过。在 android studio 2.1.2 上 :) 适用于 Android Studio 3.2.1,太棒了!仍然没有记录在任何地方!???【参考方案2】:

当前解决方案

创建文件夹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 文件中添加两个代码 sn-ps 作为依赖项:

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)

同样的答案也可以在相关问题中找到:Include .so library in apk in android studio

【讨论】:

Compile 任务已被弃用。改用JavaCompile(来自相关答案) 我应该把任务放在哪里? 请先尝试jniLibs文件夹解决方案。此任务应放入您的应用程序/库 gradle.build 文件中。 jniLibs 目录路径参考Gradle Plugin User Guide - Project Structure 另见此处(列出不同的架构子文件夹):cumulations.com/blogs/9/…【参考方案3】:

解决方案 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 - 编辑了代码。该目录可以是指向项目目录之外的 [相对] 路径。

【讨论】:

解决方案 2 对我不起作用。我收到一个构建错误:“在源集 'main' 上找不到属性 'jni'。” 秘密是“需要在与“Java”或“Assets”文件夹相同的文件夹中创建“jniLibs”文件夹。谢谢! 方法 1 让我能够正确编译,第二个在 AS 中创建了一个“cpp”文件夹并给了我关于缺少 C++ 编译器的错误 解决方案 2 必须使用 jniLibs.srcDirs,而不是 jni.srcDirs 以允许指定本机库的位置(路径可以是相对的或绝对的,甚至可以指向项目目录之外)。 对于解决方案 2,您需要将 source Sets 代码放在 android 部分下【参考方案4】:

Android Studio 中的*.so 库

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

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

效果很好

|--应用程序:

|--|--src:

|--|--|--main

|--|--|--|--jniLibs

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

|--|--|--|--|--|--.so 文件

这是项目结构。

【讨论】:

compile fileTree(dir: 'libs', include: ['.jar','.so'])中添加.so 解决了我的prb。谢谢 如果还是按照下面的解决方法,试试android ndk r10e【参考方案5】:

这是我的 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')

【讨论】:

【参考方案6】:

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/applibgperf.so 也会在那里。

在 C++ 代码上,使用:#include &lt;gperf.h&gt;

标头位置:hello-libs/distribution/gperf/include/gperf.h

库位置:distribution/gperf/lib/arm64-v8a/libgperf.so

如果您只支持某些架构,请参阅:Gradle Build NDK target only ARM

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

【讨论】:

【参考方案7】:

我已经使用打包在 jar 文件中的外部本机 lib 依赖项解决了类似的问题。有时这些架构依赖库一起打包在一个 jar 中,有时它们被拆分为几个 jar 文件。所以我写了一些构建脚本来扫描原生库的 jar 依赖项并将它们分类到正确的 android lib 文件夹中。此外,这还提供了一种下载在 maven repos 中找不到的依赖项的方法,这对于让 JNA 在 android 上运行很有用,因为并非所有本机 jar 都发布在公共 maven repos 中。

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

【讨论】:

【参考方案8】:

我有 android studio 4.1.2,当我尝试在 File -> Project Structure -> Sdk Location 中设置 ndk 路径时,即使它已经安装,它也会要求我下载 ndk,我设置了 NDK_HOME、ANDROID_NDK_HOME和 PATH 环境变量,什么都没有。唯一对我有用的是在 local.properties 中手动设置 ndk 版本,使用 ABI 及其各自的 .so 文件创建一个 jniLibs(是的,具有此确切名称)文件夹,并在构建中指定 abi 过滤器和 ndk 版本.gradle。希望这可以使其他人免于头痛。

local.properties

ndk.dir=C\:\\Users\\<user>\\AppData\\Local\\Android\\Sdk\\ndk\\22.0.7026061

build.gradle

plugins 
    id 'com.android.application'


android 
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig 
        applicationId "com.example.myapplication"
        minSdkVersion 22
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
        ndk.abiFilters 'armeabi-v7a','arm64-v8a','x86','x86_64'

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

    

    sourceSets 
        main 
            jniLibs.srcDir 'jniLibs'
        
    

    buildTypes 
        release 
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        
    

    compileOptions 
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    

    ndkVersion '22.0.7026061'

...\app\src\main\

在 jniLibs 文件夹内

【讨论】:

【参考方案9】:

使用本机库(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

【讨论】:

以上是关于如何在 Android Studio 中包含 *.so 库?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 android studio 中包含应用内图标选择器?

如何在android studio项目中包含共享库?

[在Android Studio中,构建一个Android Wear项目,如何在两个模块中包含相同的文件

当JSON对象URL字段在android studio中包含多个URL时,如何存储来自JSON对象请求的URL?

在 android studio 中包含 facebook sdk

在android studio的apk中包含.so库[重复]