Tutorial: Hosting and Referencing AAR Dependencies in a Published Android Library
Introduction
When developing and publishing an Android library, you may encounter situations where your library depends on third-party libraries distributed as AAR files. Hosting an AAR locally within your project isn’t an ideal solution(if your project is a library that will be published) because it forces other developers using your library to manually include the AAR file 😬, adding unnecessary complexity to their setup.
I faced this exact challenge in 2024 while working on a project to enhance a contactless Android payment library with support for one of the major card schemes widely used in Nigeria. The required library was only available as an AAR file, which posed a significant hurdle for seamless integration. To solve this problem, I had to find an efficient way to host the AAR independently and reference it in the published library.
This tutorial shares my approach to hosting the AAR and ensuring it can be seamlessly integrated into your published library, making the process hassle-free for you and other developers.
Step 1: Project Setup
- Create an Android library module (
paymentStandaloneAar
) where you want to include the AAR file. - Add the AAR file to a directory within your project (e.g.,
paymentStandaloneAar/libs
). Note this module could be nested within an Android app’s project. It could also be created independently.
Step 2: Configure the Library Module
In the build.gradle
file of your library module, add the AAR as an artifact to your Maven publication.
Example Configuration:
plugins {
id 'com.android.library'
id 'org.jetbrains.kotlin.android'
id 'maven-publish'
}
android {
namespace 'com.dikascode.contactless.emv_standalone'
compileSdk 33
defaultConfig {
minSdk 23
targetSdk 33
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles "consumer-rules.pro"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = '17'
}
}
task sourceJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
archiveClassifier.set('sources')
}
dependencies {
implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.11.0'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
afterEvaluate {
publishing {
publications {
paymentStandaloneAarPub(MavenPublication) {
groupId = 'com.dikascode.contactless'
artifactId = 'paymentstandaloneaar'
version = '1.0.0'
// Include the AAR file as an artifact
artifact("$rootDir/paymentStandaloneAar/paymentStandaloneExample.aar")
artifact(sourceJar)
}
}
}
}
Why afterEvaluate
and MavenPublication
are Needed
The afterEvaluate
block is required because Android Gradle Plugin applies configurations dynamically. This ensures that all Android-specific configurations (like android.sourceSets
) are fully initialized before setting up the Maven publication.
Key Details
- MavenPublication:
MavenPublication
is used to define how your library will be structured when published. It specifies the group ID, artifact ID, version, and artifacts (files) to include.
2. Artifacts:
artifact("$rootDir/paymentStandaloneAar/paymentStandaloneExample.aar")
:
- This line adds the
.aar
file as part of the published library. Without this, the AAR wouldn't be included, and the library would break if it depends on this AAR file.
artifact(sourceJar)
:
- Including a source JAR helps other developers debug or understand the library.
Why afterEvaluate
?
- The Android Gradle Plugin defines some properties dynamically, and these might not be available during the initial configuration phase. Wrapping the
publishing
block inafterEvaluate
ensures that these properties (likeandroid.sourceSets
) are available when the publication configuration is applied.
Your settings.gradle file should look like this:
pluginManagement {
repositories {
google() // Google's Maven repository
mavenCentral() // Maven Central repository
gradlePluginPortal() // For Gradle plugins
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
mavenLocal() // For local testing
maven { url 'https://jitpack.io' } // Optional: If using JitPack
}
}
rootProject.name = "MyAndroidLibrary"
include ':paymentStandaloneAar' // if your library is part of a multi-module project
Step 3: Publish the Library
- Use a repository service like JitPack or Maven Central to host your library.
- Follow the service’s guidelines for uploading the library. For JitPack:
- Push your project to a public Git repository (e.g., GitHub).
- Ensure the
maven-publish
plugin is configured correctly in your library module. - Build and publish the library via JitPack.
To learn more about how to publish Android library to JitPack.io check out this video on YouTube by Mike’s Code or read this article by Vincent Tsen
Step 4: Consume the Library
To consume your published library’s dependency:
- Add the hosted repository to the
build.gradle
file:
repositories {
google()
mavenCentral()
maven { url 'https://jitpack.io' }
}
2. Add the library dependency:
implementation 'com.nameofgitrepo.project:paymentstandaloneaar:1.0.0'
Step 5: Testing the Integration
- Create a sample app that uses your published library.
- Verify that the AAR dependency is automatically resolved and that the library functions correctly without manual inclusion of the AAR.