As Android projects scale into multi-module architectures or shared SDKs, isolating reusable features—such as custom UI components, networking engines, or analytics clients—into modular Android Archive (`.aar`) libraries becomes essential.

Unlike standard Java Archive (.jar) files that contain only compiled .class bytecode, an Android .aar package bundles compiled bytecode along with Android manifests, layouts, drawable resources, and native .so libraries. In this article, we demonstrate how to construct an Android Library module, expose public API contracts, and invoke library functions from a host application.

Quick Syntax Reference: Module Dependency Setup

Configure Gradle settings and build files to link a local library module (:mylibrary) to your main application module (:app):

settings.gradle.ktskotlin
// Include both application and library modules in project build
include(":app")
include(":mylibrary")
app/build.gradle.ktskotlin
plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}
 
dependencies {
    // Link local library module dependency
    implementation(project(":mylibrary"))
}

1. Defining Public API Contracts in the Library Module

Inside the :mylibrary module, create a public singleton SDK entry point to handle context initialization and expose public helper methods:

mylibrary/src/main/java/com/example/mylibrary/PrinterSDK.ktkotlin
package com.example.mylibrary
 
import android.content.Context
import android.widget.Toast
 
object PrinterSDK {
    private var isInitialized = false
 
    fun initialize(context: Context, apiKey: String) {
        // Validate SDK setup
        require(apiKey.isNotBlank()) { "API Key cannot be empty" }
        isInitialized = true
        Toast.makeText(context.applicationContext, "PrinterSDK Initialized", Toast.LENGTH_SHORT).show()
    }
 
    fun printMessage(context: Context, message: String): String {
        check(isInitialized) { "PrinterSDK must be initialized before calling printMessage()" }
        val formatted = "[SDK-Output] $message"
        Toast.makeText(context.applicationContext, formatted, Toast.LENGTH_LONG).show()
        return formatted
    }
}

2. Configuring build.gradle.kts for Android Library Export

The library module Gradle configuration uses the com.android.library plugin and enforces a unique namespace to prevent resource collisions:

mylibrary/build.gradle.ktskotlin
plugins {
    id("com.android.library")
    id("org.jetbrains.kotlin.android")
}
 
android {
    namespace = "com.example.mylibrary"
    compileSdk = 34
 
    defaultConfig {
        minSdk = 24
 
        // Prevent resource name collisions with host applications
        resourcePrefix("lib_")
    }
 
    buildTypes {
        release {
            isMinifyEnabled = false
            proguardFiles(
                getDefaultProguardFile("proguard-android-optimize.txt"),
                "proguard-rules.pro"
            )
        }
    }
}

3. Invoking Library Functions from the Main Application

Inside the :app module, import the library SDK package and invoke exposed public functions directly:

app/src/main/java/com/example/myapp/MainActivity.ktkotlin
package com.example.myapp
 
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.mylibrary.PrinterSDK // Import library SDK class
 
class MainActivity : AppCompatActivity() {
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        // Initialize library SDK with application context
        PrinterSDK.initialize(this, apiKey = "SDK_SECRET_KEY_12345")
 
        // Call library function
        val result = PrinterSDK.printMessage(this, "Hello from Application Module!")
        println("Returned Result: $result")
    }
}

AAR Archive Internal File Layout

  • `classes.jar`: Compiled Java/Kotlin bytecode for the library module.

  • `AndroidManifest.xml`: Library manifest merged into the main application manifest during build.

  • `res/`: Layouts, drawables, and XML resources provided by the library.

  • `R.txt` & `public.txt`: Symbol table listing exported public resource identifiers.

  • `jni/`: Native .so shared libraries compiled for target CPU architectures (arm64-v8a, x86_64).

  • `proguard.txt`: Consumer ProGuard keep rules automatically applied when consumer apps obfuscate code.