How to Build *.so Library Files into AAR Bundle in Android Studio

When making third party libraries and SDKs for Android development, you could build so files, jar files, or aar files. I prefer providing aar files for distribution since aar file is a simple zip file which includes so files, jar files, and other resources.

What’s inside aar file?

  • /AndroidManifest.xml (mandatory)
  • /classes.jar (mandatory)
  • /res/ (mandatory)
  • /R.txt (mandatory)
  • /assets/ (optional)
  • /libs/*.jar (optional)
  • /jni/<abi>/*.so (optional)
  • /proguard.txt (optional)
  • /lint.jar (optional)

The structure of aar is similar to apk.

How to create a basic aar file?

Click File > New > New Module and select Android Library:

Android library

Comparing build.gradle files, you will see the main difference is that the plugin name for aar is “com.android.library”, whereas the plugin name for application is “com.android.application”.

How to package prebuilt .so library files into .aar file?

The simplest way to add so files into an aar file is to create a folder jniLibs under src/main. And then copy *.so files into the folder:

src/main/jniLibs/<abi>/*.so

After building the module, you can open build/outputs/aar/*.aar to verify jni/<abi>/*.so.

How to automatically build native code into .aar file in Android Studio?

Let’s do something more complicated:

  1. Create a static library *.a with command line tool.
  2. Write JNI code and create a shared library *.so in Android Studio with the static library.

Static library libtwolib-first.a

Referring to the NDK sample two-libs, quickly create libtwolib-first.a with ndk-build.

Makefile Android.mk:

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := libtwolib-first

LOCAL_SRC_FILES := first.c

include $(BUILD_STATIC_LIBRARY)

Header file first.h:

#ifndef FIRST_H

#define FIRST_H

extern int first(int  x, int  y);

#endif /* FIRST_H */

Source file first.c:

#include "first.h"

int  first(int  x, int  y)

{

    return x + y;

}

Shared library libdbr.so and barcode.aar bundle

To enable NDK integration for building JNI applications,  use the new experimental plugin of Gradle instead of the original plugin.

Create a new module barcode with JNI folder and dbr.c:

#include "dbr.h"
#include <stdio.h>
#include <stdlib.h>
#include "first.h"

JNIEXPORT jint JNICALL Java_com_dynamsoft_barcode_BarcodeReader_getTestResult
        (JNIEnv *env, jobject thiz)
{
    return first(1, 2);
}

Copy libtwolib-first.a and first.h to the jni folder.

Create BarcodeReader.java:

package com.dynamsoft.barcode;

public class BarcodeReader {
    private static final String TAG = "DBR";

    public BarcodeReader() {
    }

    /**
     * Load Dynamsoft Barcode BarcodeReader shared library.
     */
    static {
        System.loadLibrary("dbr");
    }

    //////////// native methods
    public native int getTestResult();

}

Modify build.gradle:

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

model {
    android {
        compileSdkVersion 23
        buildToolsVersion "23.0.2"

            defaultConfig.with {
                minSdkVersion.apiLevel = 19
                targetSdkVersion.apiLevel = 23
                versionCode 1
                versionName "1.0"
            }
    }

    android.signingConfigs {
        create("myconfig") {
            storeFile "f:\\key\\dynamsoft.jks"
            storePassword "dynamsoft"
            keyAlias "dynamsoft"
            keyPassword "dynamsoft"
            storeType "jks"
        }
    }

    android.ndk {
        moduleName = "dbr"
        ldFlags.add("-L<static library path>")
        ldLibs.addAll(["twolib-first"])
    }
    android.buildTypes {
        release {
            signingConfig = $("android.signingConfigs.myconfig")
            minifyEnabled = true
            proguardFiles.add(file('proguard-rules.pro'))
        }
    }
    android.productFlavors {
        create ("arm8") {
            ndk.abiFilters.add("arm64-v8a")
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.0'
}

A better way to link prebuilt library:

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

model {
    repositories {
        libs(PrebuiltLibraries) {
            DynamsoftBarcodeReader {
                binaries.withType(StaticLibraryBinary) {
                    staticLibraryFile = file("lib/libDynamsoftBarcodeReader.a")
                }
            }
        }
    }

    android {
        compileSdkVersion 23
        buildToolsVersion "23.0.2"

        defaultConfig.with {
            minSdkVersion.apiLevel = 19
            targetSdkVersion.apiLevel = 23
            versionCode 1
            versionName "1.0"
        }
    }

    android.signingConfigs {
        create("myconfig") {
            storeFile "f:\\key\\dynamsoft.jks"
            storePassword "dynamsoft"
            keyAlias "dynamsoft"
            keyPassword "dynamsoft"
            storeType "jks"
        }
    }

    android.ndk {
        moduleName = "dbr"
        ldLibs.addAll(["m","log","jnigraphics"])
        stl "stlport_static"
    }

    android.sources {
        main {
            jni {
                dependencies {
                    library "DynamsoftBarcodeReader" linkage "static"
                }
            }
        }
    }

    android.buildTypes {
        release {
            signingConfig = $("android.signingConfigs.myconfig")
            minifyEnabled = true
            proguardFiles.add(file('proguard-rules.pro'))
        }
    }
    android.productFlavors {

        create ("arm7") {
            ndk.abiFilters.add("armeabi-v7a")
        }

    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.1.0'
}

Build debug and release version with Gradle:

Build release & debug with Gradle

release and debug aar files

You can download more NDK Gradle project samples from https://github.com/googlesamples/android-ndk.git

How to import .aar file to an Android project?

Create an empty Android project.

Click File > New > New Module and choose Import .JAR/.AAR Package:

import aar

Click Next to specify the file name. E.g. f:\barcode-arm8-debug.aar.

Once clicked the “Finish” button, the aar file will be packaged into your Android project as a module. Press F4 to open Project Structure, and then add the dependent module:

module dependency

Build the project. The shared library *.so that built in *.aar has been added to the generated apk file. app\build\outputs\apk\app-debug.apk\lib\<abi>\*.so.

Run the app and check the log:

Android JNI app

The native JNI code worked!

  • Woz

    Hello, if I wanted to create a library to hide the urls of a sdk with JitPack, how would that do?

  • http://www.dynamsoft.com/ Xiao Ling

    You have to write native code(JNI) if you want to use .a. The first step is to build your shared library (it’s mentioned in my article) based on the dependent .so and .a. Then you need to load the two shared libraries in Java. As for AAR file, you just need to import it into your project and use it.

  • khegde

    1. >> Why do you want to do this?….. I need to integrate with 3 3rd party libraries in my android project. They are in 3 different formats (.aar, .so and .a). If it were only .so and .a, I would have written native (C) code, but the presence of aar library is forcing me to convert .a and .so to .aar so that I can access all the three libraries from Java.
    2. Thanks for your suggestion. Will try that. Any other ideas is welcome. I doubt it, but do you know if it is possible to convert a .a into .so?

  • http://www.dynamsoft.com/ Xiao Ling

    Hi. Why do you want to do this? Only .so could be loaded by Java. All .a files should be built into a .so file. I never tried but you can put a static library to src/main/jniLibs//*.a and check whether it will work.

  • khegde

    Hello Xiao,

    Great article! I was able to successfully convert a .so library to AAR one. I now have .a library and a corresponding .h file (in C). I would like to convert this static library to an AAR module. I am having difficulty in following the steps mentioned by you. Would you mind jotting a few quick bullet points on how to achieve this?

  • http://www.dynamsoft.com/ Xiao Ling

    You can follow Google’s tutorial to build static library. https://github.com/googlesamples/android-ndk/blob/master/hello-libs/app/build.gradle

  • http://about.me/eazyigz Igor Ganapolsky

    Can you please augment your tutorial to show how to build .a (static libs) into the NDK build? With gradle experimental, one would use the `StaticLibraryBinary` type, but it doesn’t compile for me.