【问题标题】:Android native library linking against another native library from aarAndroid 本机库链接到来自 aar 的另一个本机库
【发布时间】:2015-07-23 19:33:16
【问题描述】:

我有一个奇怪的问题。我有一个 aar 库,其中包含并使用本机 .so 库。现在,我想编写另一个库,它依赖于该库,并且还具有依赖于第一个库中的本机库的本机部分。依赖库使用第一个库中的本机代码和 java 包装器。

我想知道,有什么方法可以通过标准的 gradle 依赖(使用从第一个库复制的头文件)来做到这一点?还是我必须直接从源代码构建第二个库?

为什么我需要这个: 我们有一个具有基本功能的多平台库,用于 android as aar。这个库可以在标准的安卓应用中使用,我们在多个项目中使用它,没有其他原生代码。

但在一个应用程序中,我们希望编写多平台共享应用程序代码,具体取决于该库,我希望将这些库分开。

谢谢!

【问题讨论】:

    标签: java android c++ android-ndk multiplatform


    【解决方案1】:

    注意:此答案已弃用,因为 Android Studio 不再提供 explored-aar 目录。

    要获得使用来自aar 的标头的更好解决方案,请查看库androidNativeBundle

    Here 是一个基于OpenCV 的可行示例,您可以为您的first lib 做同样的事情。

    如下准备第一个库

    打包jar*.so,并导出headers(请参阅链接项目中的文件OpenCV4Android/opencv/build.gradle,如何将标头附加到aar)。

    例如,您可以从first lib 的大楼中获得first.aar

    在其他项目中使用第一个库

    在需要时将first.aar 添加到您的其他项目中。

    allprojects {
        repositories {
            jcenter()
    
            flatDir {
                dirs '/path/to/aar'
            }
        }
    }
    
    // in your app's build.gradle
    dependencies {
        // ...
        compile 'com.example:example-with-header@aar'
        // ...
    }
    

    将您的本地库链接到本地​​构建系统中的first.aar

    如果你使用CMake,它应该是这样的

    add_library(first
    SHARED
    IMPORTED)
    
    set_target_properties(
    first
    PROPERTIES IMPORTED_LOCATION
    ../../../../build/intermediates/exploded-aar/org.example/example-debug/jni/${ANDROID_ABI}/libfirst.so
    # use find command to figure out the location of the first lib before use it, not sure if it's different in different build environment
    # for android studio gradle plugin latest version use
    # ../../../../build/intermediates/transforms/mergeJniLibs/debug/folders/2000/1f/main/lib/${ANDROID_ABI}/libfirst.so
    )
    
    # also use find command to figure the actual location of the exported header from aar
    # this might be different in your environment for different version of gradle plugin
    include_directories(build/intermediates/exploded-aar/com.example/example-debug/cpp/include)
    
    target_link_libraries( # Specifies the target library.
                           native-lib
    
                           # Links the target library to the log library
                           # included in the NDK.
                           first
                           ${log-lib} )
    

    【讨论】:

    • 这个答案不再有效,因为android studio没有创建exploded-aar目录。
    • 是的,新的Android工作室已经删除了exploded-aar目录,我在答案中推荐了一个新的方法。
    【解决方案2】:

    正如您提到的 Gradle,我假设您正在使用 最新的安卓工作室。我正在使用 1.2.2,发现它很容易 从浮动的许多教程中构建简单的 NDK 项目 周围,​​但令人沮丧的是,很难构建一个 NDK 项目 任何复杂性。我将总结我的发现,但我高度 建议阅读 this blogthis StackOverflow

    我的项目与您的项目相似,但不完全一样。我的诀窍 正在研究如何让 Android Studio 使用我的 Android.mk,然后 找到正确的 makefile 变量。希望这会有所帮助。

    现有的 Android Studio 将完全忽略任何自定义 您创建的 Android.mk 文件,而是自动生成它自己的文件。 要纠正这个问题,您必须首先破解 build.gradle 项目的脚本,位于project/app/build.gradle。 如果需要,您可能会破解顶级 build.gradle。

    这是我破解的 build.gradle。我建立在一个 Windows 盒子上,所以我 仅针对 Windows 破解了它。如果您使用的是 OSX,请取消注释这些行 或 Linux。

    project/app/build.gradle:

    //import org.apache.tools.ant.taskdefs.condition.Os
    apply plugin: 'com.android.application'
    
    android {
      compileSdkVersion 22
      buildToolsVersion "22.0.1"
    
      defaultConfig {
        applicationId "com.sample.app"
        minSdkVersion 15
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
      }
      buildTypes {
        release {
          minifyEnabled false
          proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
      }
    
      //ENABLE CUSTOM ANDROID.MK >>
      sourceSets.main.jni.srcDirs= [] //Disable automatic ndk-build.
      sourceSets.main.jniLibs.srcDir 'src/main/libs'
    
      //Call regular ndk-build script from app directory
      task ndkBuild(type: Exec) {
        workingDir file('src/main')
        commandLine getNdkBuildCmd()
      }
    
      tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
      }
    
      task cleanNative(type: Exec) {
        workingDir file('src/main')
        commandLine getNdkBuildCmd(), 'clean'
      }
    
      clean.dependsOn cleanNative
    }
    //ENABLE CUSTOM ANDROID.MK <<
    
    dependencies {
      compile fileTree(dir: 'libs', include: ['*.jar'])
      compile 'com.android.support:appcompat-v7:22.2.0'
      compile 'com.google.android.gms:play-services:7.5.0'
    }
    
    //ENABLE CUSTOM ANDROID.MK >>
    def getNdkDir() {
      if (System.env.ANDROID_NDK_ROOT != null)
        return System.env.ANDROID_NDK_ROOT
    
      Properties properties = new Properties()
      properties.load(project.rootProject.file('local.properties').newDataInputStream())
      def ndkdir = properties.getProperty('ndk.dir', null)
      if (ndkdir == null)
        throw new GradleException("NDK location not found. Define location with ndk.dir in the local.properties file")
    
      return (ndkdir)
    }
    
    def getNdkBuildCmd() {
      def ndkbuild = getNdkDir() + "/ndk-build.cmd"
    //  def ndkbuild = getNdkDir() + "/ndk-build"
    //  if (Os.isFamily(Os.FAMILY_WINDOWS))
    //    ndkbuild += ".cmd"
      return ndkbuild
    }
    //ENABLE CUSTOM ANDROID.MK <<
    

    现在我可以创建我的多库 Android.mk。这建立 两个静态链接库,然后构建最终的动态链接 前两个中的库和链接。涉及的目录 是:

    目录:

    project/
      app/
        build.gradle
        src/
          main/
            java/
            jni/
              Android.mk
              include/
              libmp3lame/
              MiniMp3/
              mp3_jni.c
              mpglib/
    

    Android.mk:

    TOP_PATH := $(call my-dir)
    
    LOCAL_PATH := $(TOP_PATH)/libmp3lame
    include $(CLEAR_VARS)
    LOCAL_C_INCLUDES := $(TOP_PATH)/include
    LOCAL_CFLAGS := -DSTDC_HEADERS
    
    LOCAL_MODULE                := libmp3lame
    LOCAL_SRC_FILES             := \
    bitstream.c \
    ...
    version.c
    
    include $(BUILD_STATIC_LIBRARY)
    MY_LOCAL_STATIC_LIBRARIES += libmp3lame
    
    LOCAL_PATH := $(TOP_PATH)/mpglib
    include $(CLEAR_VARS)
    LOCAL_C_INCLUDES := $(TOP_PATH)/include
    LOCAL_C_INCLUDES += $(TOP_PATH)/libmp3lame
    LOCAL_CFLAGS := -DSTDC_HEADERS
    LOCAL_MODULE := mpglib
    LOCAL_SRC_FILES := \
    common.c \
    ...
    tabinit.c
    
    include $(BUILD_STATIC_LIBRARY)
    MY_LOCAL_STATIC_LIBRARIES += mpglib
    
    LOCAL_PATH := $(TOP_PATH)
    include $(CLEAR_VARS)
    LOCAL_C_INCLUDES := $(TOP_PATH)/include
    LOCAL_CFLAGS := -DSTDC_HEADERS
    LOCAL_MODULE := Mp3
    LOCAL_STATIC_LIBRARIES := $(MY_LOCAL_STATIC_LIBRARIES)
    LOCAL_LDLIBS := -llog
    LOCAL_SRC_FILES := \
    ./mp3_jni.c
    
    include $(BUILD_SHARED_LIBRARY)
    

    您需要调整 Android.mk。

    【讨论】:

    • 我不是这个意思。我已经使用自定义生成文件和其他一些调整来构建霓虹灯和非霓虹灯变体,类似于您的解决方案。我的问题是,是否可以将一个本机项目与另一个 aar 库中打包的 lib 链接起来。但我想想,这是不可能的……
    【解决方案3】:

    从 Android Studio 4.0 开始,AGP(Android Gradle 插件)支持称为 Prefab 的新机制。这使用了一个专门准备的 AAR,它可以像您拥有其他外部库一样列在您的项目依赖项中,并且您可以获得从 CMake 或 ndk-build 链接到库所需的标头和构建标志。

    这类似于@alijandro 的exploded-aar approach,但它得到官方支持,并且需要更少的样板。例如。你只需要

    find_package(first REQUIRED CONFIG)
    target_link_libraries(app first::libfirst)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-12
      • 2016-07-10
      • 1970-01-01
      • 2017-04-22
      • 2014-05-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多