26

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

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

甚至可能吗?

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

4

4 回答 4

6

= 2020 年 6 月 20 日更新 =

如今,有一个不错的插件,效果很好。感谢它的作者和@Paulo Costa 指向它。

= 已过时 =

找到了以下解决问题的方法:

使用 Android Experimental Gradle 插件版本 0.9.1。这个想法是将库头和静态库放入.aar。每个架构的头文件ndkLibs/include和静态库都被放入。ndkLibs/<arch>然后,在应用程序或依赖于这个打包库的另一个库中,我们只需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')
于 2017-04-27T15:11:09.807 回答
2

手动破解 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)
    
于 2020-03-18T04:48:51.010 回答
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 文件。我不确定它是否会起作用。

于 2017-02-27T20:59:42.977 回答
0

虽然我没有亲自尝试过,但我在这里找到了一些步骤:

可能是间接的[前一段时间尝试使用共享库],我个人认为不值得:

  • 首先构建你的库以生成一个静态库,然后一个 aar [model.library 不会将 *.a 放入 libs 目录]
  • 解压缩你的 aar,并将 *.a 放入 libs 文件夹
  • 为您的头文件找到一个位置
  • 将其压缩回应用程序中的 aar,使 aar 成为您的依赖库,以便将其解压缩到 exploded-aar 文件夹中;然后出现彩色图片。
  • 将中间展开的 aar 目录添加到包含路径中我认为这太 hacky 并且将这些强加给您的客户可能不是一个好主意。

与上述黑客攻击相比,直接分发 lib 和头文件的传统方式仍然更好。对于构建库,cmake 方式要好得多,在 master-cmake 分支中检查 hello-libs,希望这会有所帮助

于 2017-03-02T13:36:37.027 回答