Android Gradle添加静态库

在传统的android ndk中,我们将指定要在Android.mk文件中链接的静态库

Android.mk

PLATFORM_PREFIX := /opt/android-ext/ LOCAL_PATH := $(PLATFORM_PREFIX)/lib include $(CLEAR_VARS) LOCAL_MODULE := library LOCAL_SRC_FILES := library.a include $(PREBUILT_STATIC_LIBRARY) LOCAL_STATIC_LIBRARIES := android_native_app_glue library 

这是我的问题

当切换到NDK的Gradle实验性插件时,我有点困惑。 分享你的想法如何链接应用程序build.gradle文件中的静态库。

我遵循了这里给出的最新的gradle实验性插件文档。

Solutions Collecting From Web of "Android Gradle添加静态库"

看看这个例子 。

  1. 告诉编译器头文件的位置(在android.ndk{} ):

    CFlags += "-I${file("path/to/headers")}".toString() cppFlags += CFlags

  2. 告诉链接器.a文件的位置(在android.ndk {}或定义的风格 – 确保添加abiFilter – 例如abiFilters += "armeabi-v7"

    ldFlags += "-L${file(path/to/library.a)}".toString() ldLibs += ["nameOfLibrary"]

    请注意,按照惯例库的名称是.a文件名中的“lib”之后的string。 例如,对于名为libNative.a的文件,您应该将ldLibs + = [“native”]添加到gradle。

  3. 创build一个新模块并使用apply plugin: 'java'来应用java插件。 在build.gradle中,编写必要的代码来获取并将.a文件放在相应的目录中(您将从您的模块中使用它)。 不要忘记在模块中使用库添加依赖项(依赖项中compile project(':libraryModule') ),并使用include ':libraryModule'include ':libraryModule'settings.gradle文件中的项目中。 如果你想放置在你的文件夹指定的模块(例如当前您的Android.mk文件),只需添加project(':libraryModule').projectDir = new File(settingsDir, 'path/to/module')

这应该做到这一点。

上面的答案是围绕Gradle先前的NDK集成不足而做的。 这个答案说明了与NDK的新的gradle集成。

看看这个针对gradle 2.9和android插件0.6.0-alpha1编写的示例 。 相对于如何提出这个问题,这个答案包含一个单独的图书馆项目。 可以探索这个function,以允许gradle在应用程序项目使用之前构build该库。 其他答案依赖于图书馆已经build成的假设。

:secondlib com.android.model.application构buildlibsecondlib.so(用System.loadLibrary(“secondlib”)加载到Java代码中)名为'secondlib'的名字很差,我想把它看作是一个.so包装器“为应用程序使用的所有其他本地库。

该共享库与由firstlib com.android.model.native构build的firstlib.a静态链接。

根据exportedHeaders子句,头文件从:firstlib中导出到任何相关项目(在本例中为secondlib)。 这种方式依赖项目知道如何链接.so / .a。 这在先前的答案中replace了CFlags + =“ – I / path / to / headers”语法。

:secondlib按照以下条款静态地链接到firstlib:

 android.sources { main { jni { dependencies { project ":firstlib" buildType "debug" linkage "static" } } // TODO(proppy): show jniLibs dependencies on .so } } 

如评论所示,这个例子是不完整的。 完成语法显示在实验android插件文档的'NDK Dependencies'部分。 在那个文档中,如何静态链接而不是dynamic链接的语法应该是清楚的。

目前有一些缺点(例如,上面显示的依赖项的buildType是默认的“debugging”,而不是正在构build的当前buildType)。

编辑:这是一个在app / build.gradle新的依赖关系语法的工作进行中的示例拉出我的一个项目:

  android.sources { main { jni { //for exportedHeaders dependencies { project ":libfoo" linkage "shared" } } jniLibs { //Where the swig wrapped library .so is. I use swig to create code to interface with libfoo.so within :app source { srcDirs 'libs' } //for file in $(model.repositories.libs.libfoo) dependencies { library "libfoo" } } } } repositories { libs(PrebuiltLibraries) { libevdev { //headers already available from our libfoo project via exportedHeaders //headers.srcDir "../libfoo/src/main/jni/" binaries.withType(SharedLibraryBinary) { sharedLibraryFile = file("../libfoo/build/intermediates/binaries/debug/lib/${targetPlatform.getName()}/libfoo.so") } } } } 

从概念上讲,apk是manifest,本机文件和类库的zip文件。 所以如果你复制静态库来输出它将工作。 所以在gradle中,你应该使用复制任务,并将这些库作为输出的一部分。 我只是用下面的我的文件,它的工作。

 task copyNativeLibs2h(type: Copy) { from(new File(getProjectDir(), 'libs')) { include '**/*.so' } into new File(buildDir, 'native-libs') } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn copyNativeLibs2h } 

即使使用实验性插件,也无法使用gradle构build静态库。 您可以使用预build的库,或者使用ndk-build构build它,并使用gradle插件将其链接到共享对象。

这里是一个例子:

假设我们有这个目录结构:

  • 项目(build.gradle,gradle.properties等)
    • jni_static(Application.mk,Android.mk,用于静态库的cpp文件)
    • 应用程序(build.gradle,src / main等)
      • jni_shared(共享库的cpp文件)

下面是project / app / build.gradle的相关部分:

 // look for NDK directory import org.apache.tools.ant.taskdefs.condition.Os Properties properties = new Properties() properties.load(project.rootProject.file('local.properties').newDataInputStream()) def ndkBuild = properties.getProperty('ndk.dir') + '/ndk-build' if (Os.isFamily(Os.FAMILY_WINDOWS)) { ndkBuild += '.cmd' } apply plugin: 'com.android.model.application' 

依赖关系,模型{compileOptions等

 // static lib is built with ndk-build def LOCAL_MODULE = "static" def appAbi = "armeabi-v7a" def ndkOut = "build/intermediates/$LOCAL_MODULE" def staticLibPath = "$ndkOut/local/$appAbi/lib${LOCAL_MODULE}.a" // To guarantee that the intermediates shared library is always refreshed, // we delete it in gradle task rmSO. task rmSO(type: Delete) { delete 'build/intermediates/binaries/debug/lib/armeabi-v7a', 'libshared.so' delete 'build/intermediates/binaries/debug/obj/armeabi-v7a', 'libshared.so' } // in file jni/Android.mk there is a section for LOCAL_MODULE=static // which builds the static library task buildStaticLib(type: Exec, description: 'Compile Static lib via NDK') { commandLine "$ndkBuild", "$staticLibPath", "NDK_APPLICATION_MK=../jni_static/Application.mk", "NDK_PROJECT_PATH=../jni_static", "NDK_OUT=$ndkOut" dependsOn rmSO } task cleanNative(type: Exec, description: 'Clean JNI object files') { commandLine "$ndkBuild", "clean", "NDK_APPLICATION_MK=../jni_static/Application.mk", "NDK_PROJECT_PATH=../jni_static", "NDK_OUT=$ndkOut" } clean.dependsOn cleanNative tasks.all { task -> // link of the shared library depends on build of the static lib if (task.name.startsWith('link')) { task.dependsOn buildStaticLib } // before build, make sure the intermediate so is not stuck there if (task.name.startsWith('package')) { task.dependsOn rmSO } } // build the wrapper shared lib around the static lib using the experimental plugin model { android.ndk { moduleName = "shared" cppFlags += "-std=c++11" ldFlags += "$staticLibPath".toString() ldLibs += "log" stl = "gnustl_static" abiFilters += "$appAbi".toString() } android.sources { main.jni.source { srcDirs = ["jni_shared"] } } } 

重要提示 :共享库的源代码应该位于单独的目录中,以便静态库的源代码不在其中或在其下。 这是因为实验性插件不能排除srcDirs下的一些文件。