How to embed dependencies in an Android library?

Hi community, I am a Unity dev who has built an Android library (.aar) to extend Unity’s functionality. This worked fine so far. My library needs some external dependencies, however. When I build my .aar, these dependencies won’t be added to my .aar file, so I used to add their .aar files manually to Unity. But this is quite cumbersome, and it’s not easy to find the .aar files of some of the dependencies only, because most developers assume that they’re just used as dependencies in the build.gradle file.

This is why I am trying to bundle the dependencies right in my own .aar file, to get everything together in one place. However, I am struggling a lot in achieving this. :frowning: I find gradle to be super complex at the least, and most of the info I get on stackoverflow seems to be outdated, due to frequent changes in gradle. I also tried to ask ChatGPT for help, but the suggestions were also not working properly.

So I am trying my luck here, with “real humans”.

Ideally, the libaries would become part of my .aar file, so I have to deal with only one .aar in Unity. However, it would also be fine to copy the .aars to a folder so I can retrieve them from there without trying to find out where I can find them online or how I could build them myself.

For copying them, I tried this approach that I found online:

task copyDependencies(type: Copy) {
    from configurations.implementation
    into "$buildDir/outputs/aar/dependencies"
}

but this resulted in the error

Resolving dependency configuration 'implementation' is not allowed as it is defined as 'canBeResolved=false'.
Instead, a resolvable ('canBeResolved=true') dependency configuration that extends 'implementation' should be resolved.

if I run this task separately.

If I try the same as dependency on build (build.dependOn), it works, but I still do not get any aars copied to the folder.

Here’s my build.gradle file:

plugins {
    id 'com.android.library'
    id 'org.jetbrains.kotlin.android'
}

android {
    namespace 'com.marblear.marbleextensions'
    compileSdk 33
    useLibrary 'org.apache.http.legacy'

    defaultConfig {
        minSdk 24

        // 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_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {
    implementation 'androidx.core:core-ktx:1.12.0'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.10.0'

    compileOnly files('libs/classes.jar')

    // I need to embed these or at least copy their .aar files:
    implementation 'com.google.code.gson:gson:2.8.9'
    implementation 'com.loopj.android:android-async-http:1.4.8'
    implementation "net.gotev:uploadservice:4.8.0"
    implementation "net.gotev:uploadservice-okhttp:4.8.0"
}

The libraries I want to bundle with my .aar (or copy to a folder at least) are the ones listed below compileOnly. The compileOnly thing is needed to compile my own code against the Unity libraries (libs/classes.jar)

Thanks in advance.

I’m not an Android developer, so do not know much about aars.
But assuming aars are like jars, don’t try to build a fat one, especially a fat library, that opens up a whole s***load of problems.

Copying the aars together is trivial though.
As the error says, implementation is not resolvable, it is only meant to declare dependencies, not to resolve them.

What you want to use for resolving is runtimeClasspath in your Copy task that should actually better be a Sync task.

If I try the same as dependency on build (build.dependOn), it works

quite unlikely, I don’t think you did what you think you did :slight_smile:

1 Like

Hi Björn, thanks for the fast response. How exactly do I do this runtimeClasspath thing? I tried to replace “implementation” with “runtimeClasspath” like this:

task copyDependencies(type: Copy) {
    from configurations.runtimeClasspath
    into "$buildDir/outputs/aar/dependencies"
}

earlier, when I saw this hint on stackoverflow. Yet this doesn’t work either:

> Could not get unknown property 'runtimeClasspath' for configuration container of type org.gradle.api.internal.artifacts.configurations.DefaultConfigurationContainer.

For a gradle noob like me, this is all super confusing.

Another question here: Is there another way to get the .aar file of an arbitrary external library referenced in the dependencies section somehow?

Some libraries host these as a build artifact on github, but others won’t (e.g. ok-http). I tried to compile this library, but its own structures was too complex, so I failed to do so.

I can only guess that these libraries are downloaded from this maven thing, but is there a way to download the .aar from there directly? (I’m not really a Java guy, as you might already have guessed.)

I tried to download okhttp from the “Maven Central” repo, in particular, but could only find version old versions (up to 2.75), but their website mentions the latest one is 4.8.0. But they don’t describe how do get it other than referencing it in the gradle file.

earlier, when I saw this hint on stackoverflow. Yet this doesn’t work either

Maybe you do it in the wrong build script?
But actually if implementation is there, runtimeClasspath should also be there.
But maybe it is different for an Android project.
Just do ./gradlew dependencies then you see all non-deprecated configurations.
I guess for Android it will be runtimeReleaseClasspath or something like that.

For a gradle noob like me, this is all super confusing.

I strongly recommend to use Kotlin DSL instead of Groovy DSL. It is by now the default DSL, you immediately get type-safe build scripts, actually helpful error messages if you mess up syntax, and amazingly better IDE support if you use a proper IDE like IntelliJ IDEA or Android Studio.

Is there another way to get the .aar file of an arbitrary external library referenced in the dependencies section somehow?

If you know in which repository it is hosted, you can just download it from there.
If the dependency is for example on Maven Central, you can just download the artifact directly using a browser.
Or if you actually did your build and the build needed the aar, you also find the artifact in the Gradle cache at <GRADLE_USER_HOME>/caches/modules-2/files-2.1/,,,.

For doing it during a build, it is indeed the easiest to use the normal resolution engine like you just try to do.

old versions (up to 2.75), but their website mentions the latest one is 4.8.0.

Which website?
Latest okhttp release is 4.12.0 and it is also available on Maven Central, but not as aar, just as jar.
But here again, I’m not an Android guy.
If you mean 2.7.5, not 2.75, you are probably looking at com.squareup.okhttp:okhttp, but they changed their coordinates to com.squareup.okhttp3:okhttp.

1 Like

Thank you so much for all these explanations, highly appreciated. I saw in the meantime that it is possible in Unity to add dependencies to Unity’s gradle template as well, so I did this now, and it worked. This way, I do not even have to copy .aar files around.

Regarding Kotlin DSL: Yes, I read about it. I just didn’t dare to do the switch, in order to not break things. I was pretty happy that everything else worked with my existing gradle files, which took me quite a while to figure out. :sweat_smile: