使用 NDK 包含预编译的静态库

Posted

技术标签:

【中文标题】使用 NDK 包含预编译的静态库【英文标题】:Include Pre-compiled Static LIbrary using NDK 【发布时间】:2015-02-16 09:12:04 【问题描述】:

我希望在我的 android Studio NDK 项目中包含一个预编译的静态库。我正在使用 Android Studio 1.0.1,在 SO 上尝试此问题的任何解决方案似乎都已过时(或涉及创建库项目并包含它)。

结构如下:

app
/--src
/--main
/--java
+--jni
+--jniLibs
   /--armeabi
       /--libpng.a
    --armeabiv7
       /--libpng.a
    ...(for each abi)

我正在尝试包含库 libpng。我尝试创建 jniLibs(根据 ph0b(真棒指南,顺便说一句)并将 libpng.a 添加到相应的 ABI 文件夹。这仍然给我错误 - 当我尝试编译时找不到 -llibpng使用以下代码:

ndk 
        moduleName "game" 
        cFlags "-std=c++11 -fexceptions -DANDROID -I$project.buildDir/../src/main/jni/include \
                -I$project.buildDir/../src/main/jni/include/png"
        ldLibs "EGL", "GLESv3", "dl", "log", "android", "libpng"
        stl "gnustl_static"

【问题讨论】:

您在 ndk.ldLibs 表达式中是否尝试过“png”。即不包括前缀'lib'。 @RobertRowntree yes :( 已经尝试过那个。还尝试将 libpng 添加到 ndk/platforms/android-21/usr/lib 中的相应平台作为最后的努力。尝试过 .so 和.a,无济于事。唯一有效的方法是将所有源文件用于 libpng 并将它们粘贴在一个目录中,并将其包含在我的 jni.srcDirs 中……非常混乱,笨重,并且需要一分钟立即建造。 我仍然对 NDK 使用 ph0b 技术,您可以使用自己的 'sourceSets.main' 覆盖 NDK 插件来覆盖框架... jni.srcDirs = [] /*禁用自动 ndk-build 调用*/ jniLibs.srcDir 'src/main/libs' 如果我不更改实际的 cpp 源文件,它根本不会增加构建时间,并根据 ph0b 使用我自己的 Android.mk 文件 这就是我现在正在做的事情,正在切换到 ph0b 的设置。从我阅读数小时后获得的信息来看,我只是不认为 Android Studio 支持我需要的东西。感谢您的意见! ph0b.com/android-studio-gradle-and-ndk-integration 如果你还没有……别忘了获取最新的 NDK。 ( 10c ) 【参考方案1】:

现在可以通过实验性插件正常工作。

有关完整说明,请参阅 this whole excellent article,这是我从中获取的,但我自己也在使用它并且它有效。

这是我的build.gradle - 请注意,在我的情况下,它是用于库项目,我使用的是静态链接而不是共享链接。

buildscript 
    dependencies
            
                classpath "com.android.tools.build:gradle-experimental:0.7.0-alpha3"
            

apply plugin: 'com.android.model.library'

model 
    repositories 
        libs(PrebuiltLibraries) 
            v8_base 
                binaries.withType(StaticLibraryBinary) 
                    staticLibraryFile = file("src/main/jni/libs/$targetPlatform.getName()/libv8_base.a")
                
            
            v8_libbase 
                binaries.withType(StaticLibraryBinary) 
                    staticLibraryFile = file("src/main/jni/libs/$targetPlatform.getName()/libv8_libbase.a")
                
            
            v8_libplatform 
                binaries.withType(StaticLibraryBinary) 
                    staticLibraryFile = file("src/main/jni/libs/$targetPlatform.getName()/libv8_libplatform.a")
                
            
            v8_nosnapshot 
                binaries.withType(StaticLibraryBinary) 
                    staticLibraryFile = file("src/main/jni/libs/$targetPlatform.getName()/libv8_nosnapshot.a")
                
            
        
    

    android 

        compileSdkVersion 23
        buildToolsVersion "23.0.2"

        sources 
            main 
                jni 
                    source 
                        srcDir "src/main/jni"
                    
                    dependencies 
                        library "v8_base" linkage "static"
                        library "v8_libbase" linkage "static"
                        library "v8_libplatform" linkage "static"
                        library "v8_nosnapshot" linkage "static"
                    
                
            
        

        ndk 
            moduleName "v8example"
            cppFlags.add("-std=c++11")
            cppFlags.add("-I$file("src/main/jni/include")".toString())
            cppFlags.add("-fexceptions")
            ldLibs.add("log")
            stl "stlport_static"
            abiFilters.add("armeabi armeabi-v7a x86")
        
    

替代方法是您使用自己调用 ndkBuild 的旧 Gradle 方法,从而使用 .mk 文件。这也可以正常工作,但是您会失去与 Android Studio 的良好集成,例如您的 jni 文件正确显示。

【讨论】:

【参考方案2】:

在 Android Studio 1.0.2 中添加 .so 库

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

【讨论】:

我已经用 .a-files(静态库)做到了这一点,但现在呢?如何在我的 java 代码中使用在这个库中声明的类和函数?【参考方案3】:

由于 ndk 支持现在在 gradle 中受到限制,您可以尝试对不同 abi 的静态库进行此操作。

    ndk 
        moduleName "game" 
        ....
        ldLibs ..., file(projectDir).absolutePath+"/src/main/jniLibs/\$(TARGET_ARCH_ABI)/libpng.a"
        ....
    

【讨论】:

【参考方案4】:

您不能只包含 .so 文件,您还需要有 src 文件夹,这些文件夹实际上提供了访问这些 .so 文件中的方法的接口。我建议不要以这种方式将您的项目耦合到库。

最好的方法是将它作为 android studio 的库模块包含在内,并丢弃 jni 文件夹以禁用 ndkbuild,并将 jnilib 指向 /libs 文件夹,方法是将以下内容添加到 build.gradle 文件中

jni.srcDirs = [] //disable automatic ndk-build call
jniLibs.srcDirs = [ 'libs' ] //no need to copy the .so files from /libs to /jniLibs folder

(检查libs目录是否也被android studio正确导入了.so文件)

将库作为模块导入会自动完成以下操作

a)yourlibrary 项目文件夹中的库文件夹,并根据 gradle 约定进行了重组 b) 导入项目(在 settings.gradle 中包含“:yourlibrary”)和 c)创建依赖项(“文件 -> 项目结构 -> 从左侧子窗口中选择主应用程序模块 -> 依赖项(最后一个选项卡) -> 按右侧的绿色“+” -> yourlibrary作为模块依赖 -> OK”)

【讨论】:

【参考方案5】:

这真的很难看,但它有效!您可以诱骗 Gradle 允许您将代码注入到生成的 Android.mk 文件中:

    ndk 
        abiFilter "armeabi-v7a"

        // We need to inject the static library into the
        // NDK build, and Gradle doesn't offer a way to directly
        // modify the Android.mk file... So we hack it!
        //
        // You can see the end result at:
        //   build/intermediates/ndk/debug/Android.mk

        moduleName "This_is_a_terrible_Gradle_hack\n" +

        "include \$(CLEAR_VARS)\n" +

        "LOCAL_MODULE := mystaticlib_prebuilt\n" +
        "LOCAL_EXPORT_C_INCLUDES := mystaticlib/include\n" +
        "LOCAL_SRC_FILES := mystaticlib/libmystaticlib.a\n" +

        "include \$(PREBUILT_STATIC_LIBRARY)\n" +

        "include \$(CLEAR_VARS)\n" +
        "LOCAL_MODULE := MyActualModule\n" +
        "LOCAL_STATIC_LIBRARIES += mystaticlib_prebuilt"

        cFlags "-std=c++11 -fexceptions -frtti -pthread"
        stl "gnustl_shared"
        ldLibs "log", "OpenSLES", "z"
    

【讨论】:

sigh 该死的 NDK 支持。你有找到静态库的文件夹结构吗? @MLProgrammer-CiM 你搞清楚文件夹结构了吗? 不,我选择了 B 计划,有点像这样:gist.github.com/eleventigers/e112fd76dd95e8e8ff5b

以上是关于使用 NDK 包含预编译的静态库的主要内容,如果未能解决你的问题,请参考以下文章

使用预编译库PREBUILT LIBRARY

Android NDK编译如何强制使用libc++.a的静态链接库

NDK下如何使用第三方静态库?

怎样添加预编译静态库 libwebrtc

android ndk-build 编译静态库libxx.a 以及Android studio openssl 静态库配置(cmake)

如何添加预编译静态库 libwebrtc