Search code examples
androidgradleandroid-gradle-pluginandroid-coordinatorlayout

How can I package my Android library so that my customer does not experience errors like "AAPT: error: attribute layout_behavior"


I made an Android library which fails to link when my customer tries to import it in their module-level build.gradle file for a project called mylocusmapsapplication. The customer's application has almost nothing in it, it was created in Android Studio by going to File > New > New Project... > Empty Activity. Then we simply added my library as a dependency. But when they tried to compile, it gave the following error:

/Users/michaelosofsky/.gradle/caches/transforms-2/files-2.1/9f0df0bf18c337fe1883aef0ec2959c5/jetified-locuslabs-android-sdk-3.0.1/res/layout/ll_levels_selector_coordinator.xml:9: AAPT: error: attribute layout_behavior (aka com.example.mylocusmapsapplication:layout_behavior) not found.

We were able to work around this error by also adding the following to their module-level build.gradle file:

implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"

However, then we received a new error:

/Users/michaelosofsky/.gradle/caches/transforms-2/files-2.1/9f0df0bf18c337fe1883aef0ec2959c5/jetified-locuslabs-android-sdk-3.0.1/res/layout/ll_levels_selector_coordinator.xml:9: AAPT: error: resource string/bottom_sheet_behavior (aka com.example.mylocusmapsapplication:string/bottom_sheet_behavior) not found.

Again we worked around that by adding another dependency to their module-level build.gradle file:

implementation "com.google.android.material:material:1.3.0-alpha02"

Then the customer was able to compile, link, and run their project.

But I'm not satisfied with this workaround. So I tried changing how my library includes those two dependencies.

In my library's module-level build.gradle file I tried changing from this:

implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
implementation "com.google.android.material:material:1.3.0-alpha02"

To this:

api "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
api "com.google.android.material:material:1.3.0-alpha02"

I re-released my library but when my customer tried the new version of my library on its own without the workaround described above, they saw the same error messages.

My library makes use of the :coordinatorlayout: and :material: libraries as follows:

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/ll_darkDarkTranslucent">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/llLevelSheetLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@null"
        app:layout_behavior="@string/bottom_sheet_behavior">

I believe the app:layout_behavior attribute is defined in the :coordinatorlayout: library and its value @string/bottom_sheet_behavior is defined in the :material: library.

Update 1: as I worked on this more with the workaround in-place, I discovered a bunch of other dependencies which had a similar problem. The following are the library my SDK depends on which caused java.lang.NoClassDefFoundError at runtime.

    implementation "androidx.coordinatorlayout:coordinatorlayout:1.1.0"
    implementation "com.google.android.material:material:1.3.0-alpha02"
    implementation "com.mapbox.mapboxsdk:mapbox-android-sdk:9.0.0"
    implementation "com.squareup.retrofit2:retrofit:2.9.0"
    implementation "com.squareup.retrofit2:converter-gson:2.9.0"
    implementation "org.kamranzafar:jtar:2.2"
    implementation "org.tukaani:xz:1.5"
    implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2"
    implementation "me.xdrop:fuzzywuzzy:1.2.0"
    implementation "androidx.fragment:fragment-ktx:1.3.0-alpha07"

I was able to find some references to a similar problem for the retrofit library and there someone used the same workaround as me: https://github.com/square/retrofit/issues/3266#issuecomment-632362066

Update 2: I received a great insight from @megasoft78 that the root cause might be the library itself which may have been packaged incorrectly like in Android library dependencies missing from POM with Gradle.

How can I package my library so that my customer does not experience these errors?


Solution

  • Thanks to @pavneet-singh, we have found the solution to this problem. @megasoft78 was correct, the root cause was that my library was incorrectly packaged. Here is the corrected module-level build.gradle file for my library:

    // This must go at the top of build.gradle
    plugins {
        id 'maven-publish'
    }
    
    // This can go anywhere in the build.gradle
    // I have removed my values wherever it says <MY_XXX> below
    project.afterEvaluate {
        publishing {
    
            // How to package the library
            publications {
                library(MavenPublication) {
                    from components.release
                    groupId = '<MY_GROUP_ID>'
                    artifactId = '<MY_ARTIFACT_ID>'
                    version = '<MY_ARTIFACT_VERSION_NUMBER>'
                }
            }
    
            // Where to publish the library (GitLab Package Registry in my case)
            repositories {
                maven {
                    url "https://gitlab.com/api/v4/projects/<MY_GITLAB_GROUP_ID>/packages/maven"
                    name "GitLab"
                    credentials(HttpHeaderCredentials) {
                        name = 'Job-Token'
                        value = System.getenv("CI_JOB_TOKEN")
                    }
                    authentication {
                        header(HttpHeaderAuthentication)
                    }
                }
            }
        }
    }
    

    The key change was to the publications block. The following incorrect block was what caused the problem:

            publications {
                library(MavenPublication) {
                    groupId = '<MY_GROUP_ID>'
                    artifactId = '<MY_ARTIFACT_ID>'
                    version = '<MY_ARTIFACT_VERSION_NUMBER>'
                    artifact bundleReleaseAar
                }
            }
    

    Note I'm using GitLab's Package Registry instead of JitPack.io because JitPack.io's customer service became unresponsive as soon as I became a paying customer.