We've an Android project with many modules, including dynamic feature modules. The build script boilerplate is currently handled by using script plugins (Gradle files that are applied by using apply from: 'something.gradle').
I am trying to migrate the script plugins to become build convention plugins, either buildSrc/ or an included build (includeBuild 'build-conventions') so that it can be applied by using plugin DSL (plugins { id 'mybuild.something-convention' }). However it fails when running ./gradlew bundleDebug saying that the base module and one of the dynamic feature modules both contain the same entry (struct.proto) with different content.
* What went wrong:
Execution failed for task ':app:packageDebugBundle'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.PackageBundleTask$BundleToolWorkAction
> Modules 'base' and '‹dynamicfeature1›' contain entry 'root/google/protobuf/struct.proto' with different content.
Please help me. I am trying to figure out and so far get these clues:
./gradlew <module>:dependencies --configuration debugRuntimeClasspath shows that the base module and the dynamic feature module have different version of com.google.protobuf:protobuf-javalite dependency. This is also the case before migrating to build convention plugins, but the resulting AAB of the dynamic feature module did not contain struct.proto entry then, so that there was no duplicate entry. Illustration of the indirect graph:
# In both module:
com.google.firebase:firebase-bom:30.3.1
└> com.google.firebase:firebase-perf-ktx:20.1.0 (c)
└> com.google.firebase:firebase-firestore:24.2.1 (c)
# In base module:
com.google.firebase:firebase-perf-ktx:20.1.0
└> com.google.protobuf:protobuf-javalite:3.17.3
# In dynamic feature module:
com.google.firebase:firebase-perf-ktx:20.1.0
└> com.google.protobuf:protobuf-javalite:3.19.2
com.google.firebase:firebase-firestore:24.2.1
└> com.google.protobuf:protobuf-javalite:3.19.2
Adding com.google.protobuf:protobuf-javalite dependency to the base module (with the same version that the dynamic feature module resolved) solves the problem so far (bundleDebug succeeds) but it sounds like a hack instead of a real solution, because it makes me need to inspect the dependency that causes the conflict and what its resolved versions are.
The dynamic feature module has dependency to com.google.firebase:firebase-firestore that bumps com.google.protobuf:protobuf-javalite to 3.19.2.
Removing com.google.firebase:firebase-firestore dependency (and all the code that needs it) from the dynamic feature module makes bundleDebug succeed.
Trying to backtrack, found out that it happens as soon as I move com.android.tools.build:gradle:<version> from /build.gradle to /build-conventions/build.gradle.
Based on the last clue, it seems a bug of Android Gradle Plugin.
It happens in 7.3.0 and 7.3.1.
It doesn't happen in 7.2.0.
So the workaround is to downgrade com.android.tools.build:gradle to version 7.2.0.
Related
I have only one dynamic feature module in my project called search, But when I try to build project, I get that Error:
[:search, :search] all package the same library [androidx.recyclerview:recyclerview].
Multiple APKs packaging the same library can cause runtime errors.
Placing each of the above libraries in its own dynamic feature and adding that
feature as a dependency of modules requiring it will resolve this issue.
Libraries that are always used together can be combined into a single feature
module to be imported by their dependents. If a library is required by all
feature modules it can be added to the base module instead.
Of Course, the first thing I did is to research about people who had the same problem And I found:
1- This Question
2- This medium article
Both Introduce the same solution (Use Android Gradle Plugin 4.0) and my project uses AGP 4.0.1, But the problem is that I have only one dynamic module called search. I don't have any other dynamic modules, even further I don't have the dependency of RecyclerView: androidx.recyclerview:recyclerview in my search gradle file, So this is maybe a transitive dependency.
Also, you can find that duplicated dependency in one of two ways:
1-Navigate to: PROJECT_NAME/module_name(In my case: search)/build/intermediates/
and then search for "deps.txt" file in that directory, Open the file and you will see all your module dependencies direct and transitive ones
2- run ./gradlew :module_name:dependencies task
If you tried to remove that duplicated line: androidx.recyclerview:recyclerview from "deps.txt" file, it gets generated again after each build.
That being said, I need some rule in my packagingOptions {} like exclude to prevent that conflict between search.aar and and any other search.* format
Can anyone help, please?
In my case, I removed the below from one of the modules
Note: not from the base module
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
Trying to find the bare minimum source and build files needed to build an android project in Android Studio. I want to publish to github and avoid uploading generated build files or binaries.
I do have a Android.gitignore from but I still see some more files getting pushed into the repo which may not be necessary. I understand the few obvious ones but about others, do I need them and if so kindly explain the usage.
So the question, do I need the following and if so then a short description of why?
root
build.gradle
gradle.properties
gradlew
gradlew.bat
settings.gradle
/app
app/build.gradle
app/proguard-rules.pro
/gradle (tested, android can re-download/generate following it if not present)
gradle/wrapper/gradle-wrapper.jar
gradle/wrapper/gradle-wrapper.properties
This question can have two different answers based on the meaning of the word needed.
First (the real one)
Assuming your project has currently those files, if your question is:
Should I commit these files on my Git repo?
The answer is yes, all of them, and I'm explaining why:
root
build.gradle -> defines the configuration for all the Gradle modules in your project (e.g. use the same remote repositories to download some Gradle plugins)
gradle.properties -> defines some optional flags used when building the app (e.g. enabling the incremental KAPT, enabling the AndroidX jetifier)
gradlew -> invokes the Gradle wrapper (which can be found under gradle/wrapper/gradle-wrapper.jar) to avoid to have Gradle installed when building your project on Darwin/Linux
gradlew.bat -> the same of gradlew but for Windows
settings.gradle -> defines the list of modules which are part of your project
app/
app/build.gradle -> defines the configuration only for your app module (e.g. its build types, its flavors, its version code and version name)
app/proguard-rules.pro -> defines the obfuscation rules when your app enables the minification
gradle/
gradle/wrapper/gradle-wrapper.jar -> provides the same version of the Gradle wrapper jar for all the users. This is very important because it forces the users to use the same version of the Gradle wrapper to compile your app
gradle/wrapper/gradle-wrapper.properties -> same as above, it defines which version of the Gradle wrapper you need
Second (the useless one)
Now, I'll give you the answer to the question:
Are these files strictly needed to compile an Android project?
To successfully compile an Android project with Gradle you just need the root build.gradle if you have Gradle installed on your machine or build.gradle + the wrapper files if you have not Gradle installed on your machine.
Theoretically you can:
put your application code in the root project and that avoids you one build.gradle and settings.gradle
disable the obfuscation and that avoids you proguard-rules.pro
remove gradle.properties and set the properties via command line
Obviously this solution won't happen on a real project scenario.
In recent release of our library we decided to add some kotlin-dsl features to our build, though for now we've added buildSrc build.gradle.kts and Dependencies.kts file containing libraries versions for easier use across all modules.
The problem is that this version builds successfuly on jitpack, but downloaded jars are empty. How do I fix this? Also all the resource files are present. The build log file also differs much from previous ones.
Problematic build log file
Working build log file
A link to library on jitpack: https://jitpack.io/#netigenkluzowicz/api_android
Github link
branch to reproduce these build problems is feature/kotlin, we're working to fix it on fix/jitpack-build branch
To Reproduce
Add this dependency to an Android project, sync and check classes.jars
implementation 'com.github.netigenkluzowicz:api_android:2.4.1'
What we did before this problem started to occur:
Added buildSrc directory with build.gradle.kts and Dependencies.kts.
We also extracted android { } block from our modules build.gradle files, it is now applied from android.gradle file.
I've already went through jitpack issues on github, all I found so far are build errors with kotlin-dsl from late 2018. Was following this guide to make a use of kotlin-dsl, though due to having issues with android { } block I didn't migrate all of our gradle files.
I have multiple modules in a project. I try to create a new module (Phone & Tablet Module) within the project. But when the Gradle tries to sync, I get the error:
Error:(1, 0) Due to a limitation of Gradle’s new variant-aware dependency management, loading the Android Gradle plugin in different class loaders leads to a build error.
This can occur when the buildscript classpaths that contain the Android Gradle plugin in sub-projects, or included projects in the case of composite builds, are set differently.
To resolve this issue, add the Android Gradle plugin to only the buildscript classpath of the top-level build.gradle file.
In the case of composite builds, also make sure the build script classpaths that contain the Android Gradle plugin are identical across the main and included projects.
If you are using a version of Gradle that has fixed the issue, you can disable this check by setting android.enableBuildScriptClasspathCheck=false in the gradle.properties file.
To learn more about this issue, go to https://d.android.com/r/tools/buildscript-classpath-check.html.
Some methods that I tried are:
Making the buildscript classpaths identical among modules.
Removing everything from the module's Gradle in order that it syncs.
Importing a module instead of creating a new one.
When I try to run my android application on an Android device, the gradle console reports the following error:
Error:Execution failed for task ':app:transformClassesWithJarMergingForDebug'.
> com.android.build.api.transform.TransformException: java.util.zip.ZipException: duplicate entry: com/loopj/android/http/AsyncHttpClient$1.class
When I search for the "AsyncHttpClient" class, I see that it's indeed being found in two separate locations:
/Users/Afflatus/.gradle/caches/modules-2/files-2.1/com.loopj.android/android-async-http/1.4.9/5d171c3cd5343e5997f974561abed21442273fd1/android-async-http-1.4.9-sources.jar!/com/loopj/android/http/AsyncHttpClient.java
/Users/Afflatus/.ideaLibSources/android-async-http-1.4.9-sources.jar!/com/loopj/android/http/AsyncHttpClient.java
The first path seems to suggest it's a "cache" file... so I've tried invalidating & restarting my cache, but both files are still there after the gradle gets rebuilt and I try to run the application. I've read in alternate posts that it can be resolved by deleting one of the files... So I went to the cache location and deleted all the files found in the "1.4.9" folder... unfortunantly after reopening Android Studio, a new cache file gets created and I get the same error.
Other posts (here, here,here, and here) suggest if I add "./gradlew clean" to the root directory it would rebuild the gradle again just for the run (as far as I understand). So I tried doing that as well:
Which made my app's folder look like this:
But unfortunantly, that didn't help things I still get the same error. What am I doing wrong? What should I be doing?
I added this line to my gradle.properties file and my app worked
android.enableJetifier=true
Sometimes duplicate classes exception means that one of your dependencies uses implicitly the older or newer (with +) version of some library you also use in your project,
To resolve this issue you may add such block of code (put your library version after 'force') to your build.gradle file (Module:app):
configurations {
all {
resolutionStrategy {
// do not upgrade above 3.12.0 to support API < 21 while server uses
// COMPATIBLE_TLS, or okhttp3 is used in project
force 'com.squareup.okhttp3:okhttp:3.12.0'
force 'com.squareup.okhttp3:logging-interceptor:3.12.0'
}
}
}
You may also exclude some group from your dependencies.
For a single dependency you way write:
dependencies {
// example
implementation('log4j:log4j:1.2.15') {
exclude group: 'javax.jms', module: 'jms'
}
}
Tested to work on Android Studio with Gradle Plugin version 3.4.2 and Gradle version 5.4.1.
Credits go to Dimitar Dimitrov and Schalk Cronjé from gradle org discussion group
That's because you have added some library two times in libs folder, this could happen sometimes when you have multiple versions of the same library in the libs folder. Check it and remove any duplicate jar files.
And the second option could be you have also added the dependency in gradle.build and also have a jar in libs folder.
So check both places and remove duplicate entries and then clean and build APK again.
Delete files with duplicate jar extensions in the libs folder. However, if there are no duplicate files and there is still a "Duplicate classes" error, look for the name in the rest of the "Duplicate classes ...." clause in the error section. For example, "duplicated classes 'dagger' bla bla". Delete the file named 'dagger' from the libs folder. (Be careful not to delete it with shift.)
In my case, I am using sensorocloud.jar and the compile 'com.loopj.android:android-async-http:1.4.9' in my gradle which caused the same error as yours. Because sensoro cloud SDK used loopj's async-http.
I managed to solve it by manually removing the duplicate .class files in the jar file. (i.e.
changing the extension from jar to zip
extract it
remove the com.loopj.android .class files)
(P.S. I have tried to search through the web to see if I could exclude certain class of a jar in gradle, but not succeed, e.g. I referenced this SO post)
This error can be caused by several things;
misconfigured package name
Activity views that is not well binded. - simply go to your launcher activity view and ensure context is defined well e.g "com.yourdomain.package"
Re-create your BuildConfig and set it up well.
Check if your project build.gradle. There it might be some maven duplicate dependency
Here's another situation that can cause duplicate class during the mergeDexClasses task. This can happen with later versions of android gradle.
If your build.gradle.kts script has a dependency in the form:
implementation(project(":mylib", configuration="default"))
that can cause duplicate classes. The correction is simple. Just change it to:
implemenation(project(:mylib"))
Here's the Android Studio's Team explanation:
Having both project(":lib") and project(path: ":lib", configuration: "default") in the runtime classpath means that AGP gets both build/classes/java/main and build/libs/lib.jar (run ./gradlew :lib:outgoingVariants --all to verify). Because paths differ, we'll get 2 dexing transforms happening: 1 incremental that produces dex per class under build/.transforms (the one processing dir) and another one which produces single dex (the one processing jar). Later on during merging this causes failure.
AGP never publishes to the default configuration, in fact java-library plugin does it only so it does not break older build scripts. Having an explicit configuration name used in the dependency declaration is discouraged and Gradle attributes should be used instead.
In an older version of AGP, I ran into a problem where adding the configuration value "default" fixed some issue I was having. Well that no longer works, and adding the "default" configuration you can get duplicate classes.