Development of mobile applications on the Android platform often requires the use of third-party modules, which are not always available in source code form. In such cases, developers are faced with the need to integrate ready-made compiled modules packaged in .aarformat. These files contain not only bytecode, but also resources, manifests and native libraries, which makes them more complex to include compared to regular JAR archives.
The modern ecosystem Android Studio provides several ways to introduce such dependencies into a project, each of which has its own advantages and disadvantages. The specific method you choose depends on whether you plan to use the library in one project or whether you plan to distribute it for use in multiple applications at the same time. Understanding the structure Gradle and correctly setting up file paths are critical steps for successfully building a project without compilation errors.
In this article we will analyze in detail all the current connection methods, from simply copying files to setting up a local repository. You will learn how to correctly declare dependencies in assembly files, how to avoid version conflicts, and what pitfalls can await you when working with native code inside AAR modules.
What is an AAR file and its difference from JAR
Format AAR (Android Archive) is a standard archive specifically designed for distributing libraries in the Android ecosystem. Unlike classic JARfiles, which contain exclusively Java classes, the AAR archive includes the full structure of the Android project. This means that it can contain resource files such as interface layouts, string constants, drawable images, and even style files.
In addition, AAR can contain native libraries (.so files) for various processor architectures, which makes it indispensable when working with heavy computing or specific hardware. If you try to include AAR as a regular JAR dependency, the project builder will simply ignore the resources and native code, which will cause the application to crash when launched with an error ResourcesNotFoundException.
The archive structure looks like this:
- ๐ AndroidManifest.xml โ description of access rights and library components.
- ๐ classes.jar โ compiled Java/Kotlin code libraries.
- ๐ res/ โ folder with resources (layout, values, drawable).
- ๐ R.txt โ list of all resource identifiers used in the library.
- ๐ libs/ โ folder for additional JAR dependencies of the library itself.
It is important to understand that when connecting such a library, the build system automatically merges manifests of the main application and library into one final file. This can cause conflicts if both files have the same permissions declared or components with identical names. Always check the contents of the AAR before integration to avoid unexpected errors at the stage of merging manifests.
โ ๏ธ Warning: Some older versions of libraries may not contain metadata about dependencies inside the AAR. In this case, you will have to manually register all transitive dependencies in your
build.gradle.
How to view the contents of AAR?
The AAR file is a regular ZIP archive. You can rename the file extension from .aar to .zip and open it with any archiver (WinRAR, 7-Zip, standard macOS or Linux archiver). This will allow you to quickly check the availability of the necessary resources or native libraries before connecting.
Method 1: Connect as a local file dependency
The easiest and fastest way to add a library to a project is to place the file directly in your application directory. This method is ideal for prototyping or cases where the library is used only in one specific project and is not planned for reuse. You don't need to set up complex repositories, just copy the file to the desired folder.
First, create a directory libs in the root of your application module (usually a folder app). If such a folder already exists, simply place your file there .aar. After this, you need to open the module assembly file build.gradle (module level, not project) and add a dependency declaration. The syntax depends on whether you are using Groovy or Kotlin DSL scripts.
For Groovy projects, add the following line to the block dependencies:
implementation files('libs/your-library-name.aar')
If your project is configured to use Kotlin DSL (files build.gradle.kts), the syntax will look slightly different, but the essence is the same same. Make sure the file path is correct relative to the module root. After making changes, be sure to click the button Sync Now in the top panel of Android Studio so that Gradle scans the file system and picks up the new dependency.
โ๏ธ Checking the file connection
However, this approach has a significant drawback: the files in the folder libs are not always correctly indexed by the version control system if you did not add them explicitly to .gitignore or, conversely, did not commit them. In addition, when updating the library, you will have to manually replace the file in the folder and monitor versioning, which can lead to chaos in the project during team development.
Method 2: Setting up a local Maven repository
A more professional and scalable approach is to publish the AAR file to a local Maven repository. This method simulates working with remote storage, such as Maven Central or Google Maven, but all the data is stored on your hard drive. This allows you to use the standard syntax for including dependencies implementation 'group:name:version', which makes the code cleaner and more understandable.
To implement this method, you first need to create a directory structure corresponding to the Maven coordinates. Typically this looks like a path libs/com/example/library/1.0.0/, where com.example.library is the group ID, and 1.0.0 is the version. In this folder you need to place the AAR file itself and the POM file, which describes the metadata and dependencies of the library. Although creating a POM manually is possible, it is a labor-intensive process.
It is much more convenient to use a plugin maven-publish in the library project itself (if you have the source code) or use a command line utility for deployment. After preparing the files, you need to declare the repository in the project settings. Open the file settings.gradle (or settings.gradle.kts) in the root of the project and add the block dependencyResolutionManagement.
Configuration example for Groovy:
dependencyResolutionManagement {repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
repositories {
google()
mavenCentral()
maven { url = uri("$rootDir/libs") }
}
}
Now in the file build.gradle application module you can connect the library in the same way as if it were in Internet:
implementation 'com.example.library:my-awesome-lib:1.0.0'
โ ๏ธ Attention: Make sure that the path to the local repository is absolutely correct. Using relative paths can lead to build errors when moving the project to another computer or to another directory.
Solving problems with transitive dependencies
One โโof the most common problems when working with AAR is the lack of transitive dependencies. If the library you are connecting itself depends on other libraries (for example, on Retrofit or Gson), these dependencies are not always automatically pulled into the project, especially when connecting via files(). As a result, the compiler produces errors stating that it cannot find classes from missing libraries.
To solve this problem, you need to carefully study the documentation for the plug-in library or analyze its POM file, if available. You will have to manually add any missing dependencies to your dependencies block. This requires understanding exactly which versions of libraries are compatible with your version of the AAR module. build.gradle. This requires understanding which library versions are compatible with your version of the AAR module.
Below is a table illustrating typical dependencies and how they are declared:
| Library inside AAR | Required action | Declaration example in Gradle |
|---|---|---|
| OkHttp 3 | Add manually | implementation 'com.squareup.okhttp3:okhttp:4.9.0' |
| AndroidX Core | Check version | implementation 'androidx.core:core-ktx:1.6.0' |
| Gson | Add manually | implementation 'com.google.code.gson:gson:2.8.8' |
| Material Components | Synchronize version | implementation 'com.google.android.material:material:1.4.0' |
Using the tool dependencies in Gradle helps to visualize dependency tree and find breaks. You can run the task ./gradlew app:dependencies in the terminal to see the complete connection graph. If you see red marks or missing nodes in the tree for your AAR library, then these are the components that need to be added explicitly.
Use the 'dependency-graph-generator' plugin to visualize complex dependency trees. This will help you quickly find version conflicts when two different libraries require different versions of the same component.
Version conflicts and class duplication
When integrating multiple AAR libraries or mixing local files with remote dependencies, there is a high risk of version conflicts. The situation gets worse if different libraries use different versions of the same components, such as AndroidX support. The Gradle builder will default to the newest version, which can lead to unstable operation of an older library designed for a different API.
To diagnose such problems, pay attention to the warnings in the window Build. Often there are messages like Conflict with dependency. They cannot be ignored, as this can lead to a crash of the application during execution (Runtime Exception). In such cases, it is necessary to force a single version for all modules that use the conflicting dependency.
This can be done using the mechanism resolutionStrategy in the block configurations.all. This approach allows you to centrally manage library versions without having to list them on every dependency line. An example setup looks like this:
configurations.all {resolutionStrategy {
force 'com.google.android.gms:play-services-maps:17.0.0'
}
}
Another common problem is class duplication, when the same class is present in two different AAR files or in the AAR and in the main project. In this case, the build will fail with an error app type already present. The solution is to exclude a duplicate module from one of the dependencies using a block exclude.
Example of excluding a group of modules:
implementation ('com.example:problematic-lib:1.0') {exclude group: 'com.google.android.gms', module: 'play-services-location'
}
Centralized version control through resolutionStrategy is the best way to avoid Dependency Hell in large projects with many AAR libraries.
Frequent errors and their elimination
Even if all instructions are followed, developers often encounter errors that are not obvious at first glance. One such error is the incorrect location of the AAR file. Gradle is case sensitive in paths and file names, especially on Linux and macOS operating systems, while Windows can ignore this, creating the illusion of work.
Another common problem is with Gradle caching. Sometimes, after replacing the AAR file with a new version with the same name, Studio continues to use the old version from the cache. Visually the file has been updated, but the classes inside have not changed. In such situations, clearing the cache through the menu File โ Invalidate Caches / Restart or executing the command ./gradlew clean in the terminal helps.
It is also worth remembering about proxying. If your corporate network uses a proxy server and you try to connect an AAR that has transitive dependencies from the Internet, the build may hang or throw a timeout error. Make sure that the proxy settings are correctly specified in the file gradle.properties or in the IDE settings.
โ ๏ธ Attention: The Android Studio interface and the structure of Gradle scripts may change with the release of new versions. Always check the official Google documentation if the standard settings paths do not match those described in the article.
If you receive an error Unsupported class file major version, this means that the Java versions are incompatible. The AAR library may have been compiled against a newer version of the JDK than the one used in your project. Check the settings compileOptions and make sure that sourceCompatibility and targetCompatibility meet the library requirements.
What to do if AAR is not visible in autocompletion?
Try to manually import the class into Java/Kotlin file. If the import is underlined in red but the file physically exists, run the "Sync Project with Gradle Files" command. If it doesnโt help, delete the .gradle folder in the project root and do a complete rebuild.
FAQ: Questions and answers about connecting AAR
Is it possible to connect several AAR files with the same name?
No, in the same folder libs There should be no files with the same names, even if they are in different subfolders, as long as you refer to them the same in Gradle. Each library must have a unique filename or path so that the builder can differentiate between them. It's better to rename the files by adding the version or module name.
Why does the application crash on startup after connecting AAR?
Most often this is due to the lack of necessary permissions in AndroidManifest.xml or a conflict between versions of support libraries. Check the logs in Logcat immediately after the crash - the specific reason will be indicated there, for example NoClassDefFoundError or SecurityException. Also make sure you are not using legacy Support Library with AndroidX without Jetifier enabled.
How to decompile AAR to view the code?
You can rename the file to .zip and extract classes.jar. Then use tools like JD-GUI or Luyten to view the decompiled Java code. However, be aware that variable names may be obfuscated if the library was protected by ProGuard or R8 before compilation.
Does including AAR affect the size of the resulting APK?
Yes, the APK size will increase by the size of the AAR file plus the size of all its transitive dependencies. If the library contains resources for all screen densities and languages, and you only use a subset of them, consider enabling android.enableResourceOptimizations or using the Android App Bundle to optimize size when publishing.
Can AAR be used in a library rather than in an app?
Yes, you can include AAR in an "Android Library" type module. In this case, the dependencies will be transitively passed to the application that will include your library. However, be careful about exposing AAR internal classes through your library's public API so as not to create tight coupling.