使用 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 包含预编译的静态库的主要内容,如果未能解决你的问题,请参考以下文章
Android NDK编译如何强制使用libc++.a的静态链接库
android ndk-build 编译静态库libxx.a 以及Android studio openssl 静态库配置(cmake)