Android本机库从aar链接到另一个本机库

bar*_*cha 9 c++ java android multiplatform android-ndk

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

我想知道,有没有办法,如何通过标准gradle依赖(从第一个lib复制的头文件)来做到这一点?或者让我直接从源代码构建第二个库?

为什么我需要这个:我们有一个基本功能的多平台lib,对于android as aar.这个lib可以在标准的android应用程序中使用,我们在多个项目中使用它,它没有其他本机代码.

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

谢谢!

ali*_*dro 6

这是一个可行的基本示例OpenCV,您可以为您做同样的事情first lib.

准备第一个lib如下

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

你可以first.aar从建筑物中获得first lib.

在您的其他项目中使用第一个lib

first.aar在需要时添加其他项目.

allprojects {
    repositories {
        jcenter()

        flatDir {
            dirs '/path/to/aar'
        }
    }
}

// in your app's build.gradle
dependencies {
    // ...
    compile 'com.example:example-with-header@aar'
    // ...
}
Run Code Online (Sandbox Code Playgroud)

将本机库链接到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} )
Run Code Online (Sandbox Code Playgroud)


Tea*_*art 1

正如您提到的 Gradle,我假设您正在使用最新的 Android Studio。我使用的是 1.2.2,发现从许多教程中构建简单的 NDK 项目很容易,但构建任何复杂的 NDK 项目却非常困难。我将总结我的发现,但我强烈建议阅读 此博客 和StackOverflow。

我的项目和你的类似,但不完全一样。对我来说,诀窍是弄清楚如何让 Android Studio 使用我的 Android.mk,然后找到正确的 makefile 变量。希望这会有所帮助。

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

这是我破解的 build.gradle。我是在 Windows 机器上构建的,所以我只针对 Windows 进行了修改。如果您使用的是 OSX 或 Linux,请取消注释这些行。

项目/应用程序/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 <<
Run Code Online (Sandbox Code Playgroud)

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

目录:

project/
  app/
    build.gradle
    src/
      main/
        java/
        jni/
          Android.mk
          include/
          libmp3lame/
          MiniMp3/
          mp3_jni.c
          mpglib/
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

您需要调整 Android.mk。