Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android native library linking against another native library from aar

I have a curious question. I have an aar library, which contains and uses native .so library. Now, I want to write another lib, which depends on that library and also has native part depending on native lib from the first lib. The dependent library uses both the native code and java wrappers from the first lib.

I wonder, is there any way, how to do this by standard gradle dependency(with copied headers files from the first lib)? Or have I to build the second lib directly from the sources?

Why I need this: We have a multiplatform lib with basic functionality, for android as aar. This lib can be used in standard android app and we use it in multiple projects, which have no another native code.

But in one app we want to write multiplatform shared app code, depending on that lib and I want to have these libs separated.

Thanks!

like image 674
barbucha Avatar asked Jul 23 '15 19:07

barbucha


People also ask

What is the difference between AAR and jar?

Unlike JAR files, AAR files offer the following functionality for Android applications: AAR files can contain Android resources and a manifest file, which allows you to bundle in shared resources like layouts and drawables in addition to Java classes and methods.

How do I extract an AAR file?

In android studio, open the Project Files view. Find the . aar file and double click, choose "arhcive" from the 'open with' list that pops up. This will open a window in android studio with all the files, including the classes, manifest, etc.

What is Jnilibs?

jni/libs folder is where your shared library files are built from the C/C++ sources.


2 Answers

NOTE: This answer is deprecated, since Android Studio on longer provide explored-aar directory.

For a better solution to use headers from aar, check the library androidNativeBundle

Here is a workable example basic on OpenCV, you can do the same for your first lib.

Prepare first lib as following

Package the jar, *.so, and exported headers (see the file OpenCV4Android/opencv/build.gradle in the linked project how to append the headers to aar).

You get first.aar for example from the building of first lib.

Using first lib in your other projects

Add the first.aar in your other projects when you needed.

allprojects {
    repositories {
        jcenter()

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

// in your app's build.gradle
dependencies {
    // ...
    compile 'com.example:example-with-header@aar'
    // ...
}

Link against your native library to the first.aar from your native build system.

If you use CMake, it should look like this

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} )
like image 63
alijandro Avatar answered Nov 07 '22 04:11

alijandro


As you mentioned Gradle, I am assuming you are using the latest Android Studio. I am using 1.2.2 and found it easy to build the simple NDK projects from the many tutorials floating around, but frustratingly difficult to build an NDK project of any complexity. I will summarize what I found, but I highly suggest reading this blog and this StackOverflow.

My project is similar to yours but not exactly. The trick for me was figuring out how to make Android Studio use my Android.mk, then finding the right makefile variables. Hopefully this will help.

The stock Android Studio will completely ignore any custom Android.mk file you create, and instead auto-generate its own. To correct this, you must first hack the build.gradle script for your project, located at project/app/build.gradle. You could probably hack the top-level build.gradle, if desired.

This is my hacked build.gradle. I build on a Windows box, so I hacked it for Windows only. Uncomment the lines if you are using OSX or 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 <<

Now I can create my multi-library Android.mk. This builds two static-link libraries, then builds the final dynamic-link libraries and links in the first two. The directories involved are:

Directories:

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)

You will need to tweak the Android.mk.

like image 27
TeasingDart Avatar answered Nov 07 '22 02:11

TeasingDart