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//*.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//*.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!