适用于本机库的Android AAR包

时间:2016-02-01 21:36:17

标签: android android-ndk android-gradle aar maven-central

我正在寻找一种将本机库打包成AAR包的方法,因此可以通过gradle脚本中的依赖项声明来使用它。

本机库是指.cpp文件集或编译的静态库和一组头文件。所以,我的意思是应用程序本身将从本机代码调用库,而不是从Java调用。换句话说,库需要编译应用程序的本机代码。这样就可以轻松管理本机代码的依赖关系。

甚至可能吗?

到目前为止,我只能找到很多关于如何使用.so文件及其Java接口创建JNI本机库的AAR的问题/示例,因此lib只是一个带有本机实现的Java库,但这不是什么我需要。

4 个答案:

答案 0 :(得分:3)

找到了以下针对此问题的hacky解决方案:

使用Android Experimental Gradle插件版本0.9.1。 我们的想法是将库头和静态库放入.aar。 对于每个体系结构,标头都放到ndkLibs/include和静态库到ndkLibs/<arch>。然后,在应用程序或依赖于这个打包的lib的另一个lib中,我们只需将ndkLibs目录从AAR提取到项目中的build目录。请参阅下面的示例gradle文件。

带有注释的库的build.gradle文件:

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

model {
    android {
        compileSdkVersion = 25
        buildToolsVersion = '25.0.2'

        defaultConfig {
            minSdkVersion.apiLevel = 9
            targetSdkVersion.apiLevel = 9
            versionCode = 1
            versionName = '1.0'
        }
        ndk {
            platformVersion = 21
            moduleName = "mylib"
            toolchain = 'clang'
            abiFilters.addAll(['armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64', 'mips', 'mips64']) //this is default
            ldLibs.addAll(['android', 'log'])
            stl = 'c++_static'
            cppFlags.add("-std=c++11")
            cppFlags.add("-fexceptions")
            cppFlags.add("-frtti")

            //Add include path to be able to find headers from other AAR libraries
            cppFlags.add("-I" + projectDir.getAbsolutePath() + "/build/ndkLibs/include")
        }

        //For each ABI add link-time library search path to be able to link against other AAR libraries
        abis {
            create("armeabi") {
                ldFlags.add("-L" + projectDir.getAbsolutePath() + "/build/ndkLibs/armeabi")
            }
            create("armeabi-v7a") {
                ldFlags.add("-L" + projectDir.getAbsolutePath() + "/build/ndkLibs/armeabi-v7a")
            }
            create("arm64-v8a") {
                ldFlags.add("-L" + projectDir.getAbsolutePath() + "/build/ndkLibs/arm64-v8a")
            }
            create("x86") {
                ldFlags.add("-L" + projectDir.getAbsolutePath() + "/build/ndkLibs/x86")
            }
            create("x86_64") {
                ldFlags.add("-L" + projectDir.getAbsolutePath() + "/build/ndkLibs/x86_64")
            }
            create("mips") {
                ldFlags.add("-L" + projectDir.getAbsolutePath() + "/build/ndkLibs/mips")
            }
            create("mips64") {
                ldFlags.add("-L" + projectDir.getAbsolutePath() + "/build/ndkLibs/mips64")
            }
        }
    }

    //Configure this library source files
    android.sources {
        main {
            jni {
                //This does not affect AAR packaging
                exportedHeaders {
                    srcDir "../../src/"
                }

                //This tells which source files to compile
                source {
                    srcDirs '../../src'
                }
            }
        }
    }
}

//Custom Maven repository URLs to download AAR files from
repositories {
    maven {
        url 'https://dl.bintray.com/igagis/android/'
    }
}

//Our custom AAR dependencies, those in turn are also packed to AAR using the same approach
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'io.github.igagis:libutki:+'
    compile 'io.github.igagis:libsvgdom:+'
    compile 'org.cairographics:cairo:+'
}


//===================================
//=== Extract NDK files from AARs ===
//This is to automatically extract ndkLibs directory from AAR to build directory before compiling any sources
task extractNDKLibs {
    doLast {
        configurations.compile.each {
            def file = it.absoluteFile
            copy {
                from zipTree(file)
                into "build/"
                include "ndkLibs/**/*"
            }
        }
    }
}
build.dependsOn('extractNDKLibs')
tasks.whenTaskAdded { task ->
    if (task.name.startsWith('compile')) {
        task.dependsOn('extractNDKLibs')
    }
}



//=================================
//=== pack library files to aar ===
//This stuff re-packs the release AAR file adding headers and static libs to there, but removing all shared (.so) libs, as we don't need them. The resulting AAR is put to the project root directory and can be uploaded to Maven along with POM file (you need to write one by hand).

def aarName = name

task copyNdkLibsToAAR(type: Zip) {
    baseName = aarName
    version = "\$(version)"
    extension = 'aar.in'
    destinationDir = file('..') //put resulting AAR file to upper level directory

    from zipTree("build/outputs/aar/" + aarName + "-release.aar")
    exclude('**/*.so') //do not include shared libraries into final AAR
    from("../../src") {
        exclude('makefile')
        exclude('soname.txt')
        exclude('**/*.cpp')
        exclude('**/*.c')
        into('ndkLibs/include')
    }
    from("build/intermediates/binaries/debug/lib"){
        include('**/*.a')
        into('ndkLibs')
    }
}

build.finalizedBy('copyNdkLibsToAAR')

答案 1 :(得分:1)

手动修改gradle脚本是可行的,但是很痛苦且容易出错。

我最近发现了一个插件,它在添加依赖项时将标头神奇地捆绑到AAR文件中,并提取它们并设置构建脚本:https://github.com/howardpang/androidNativeBundle

在可重复使用的库上:

  • 添加导出插件:

    apply plugin: 'com.ydq.android.gradle.native-aar.export'
    
  • 定义头文件的位置:

    nativeBundleExport {
        headerDir = "${project.projectDir}/src/main/jni/include"
    }
    

在使用它的模块上:

  • 添加导入插件:

    apply plugin: 'com.ydq.android.gradle.native-aar.import'
    
  • include ${ANDROID_GRADLE_NATIVE_BUNDLE_PLUGIN_MK}添加到Android.mk中依赖于它的每个模块中:

    include $(CLEAR_VARS)
    LOCAL_SRC_FILES := myapp.cpp \
    LOCAL_MODULE := myapp
    LOCAL_LDLIBS += -llog
    include ${ANDROID_GRADLE_NATIVE_BUNDLE_PLUGIN_MK}
    include $(BUILD_SHARED_LIBRARY)
    

答案 2 :(得分:0)

Link开始,它看起来不可能。我粘贴在内容之下:

AAR文件剖析

AAR文件的文件扩展名为.aar,Maven工件类型也应该是aar。该文件本身是一个zip文件,包含以下必填项:

  • /AndroidManifest.xml
  • /classes.jar
  • / res /
  • /R.txt

此外,AAR文件可能包含以下一个或多个可选条目:

  • /资产/
  • /libs/name.jar
  • /jni/abi_name/name.so(其中abi_name是Android支持的ABI之一)
  • /proguard.txt
  • /lint.jar

如上所述,强制性条目包括一个罐子。但是,您可以通过解压缩aar并再次拉回来手动删除jar文件来尝试。我不确定它是否会起作用。

答案 3 :(得分:0)

虽然我没有亲自尝试过,但我找到了许多步骤here

可能间接[曾经尝试使用共享库],我个人认为不值得:

  • 首先构建你的lib以生成一个静态库,并且一个aar [model.library不会将* .a放入libs目录] [/ li>
  • 解压缩你的aar,并将* .a放入libs文件夹
  • 为您的标题文件找到一个位置
  • 将其拉回到你的应用程序中,然后将其作为你的依赖库,这样它就会被提取到爆炸的文件夹中;然后出现了彩色图片。
  • 将中间爆炸的aar目录添加到include路径中 我认为将它们强加给您的客户实在太糟糕了,也许不是一个好主意。
与上面的黑客攻击相比,传统的直接分发lib和头文件的方式仍然更好。 对于构建库,cmake方式要好得多,在master-cmake分支中检查hello-libs,希望这有帮助