Exclude subproject in Gradle - android

I have two library projects, A and B, both depending on a third library project C.
I am trying to use both A and B in my app project by having the following in my app/build.gradle:
implementation project(':libraryA')
implementation project(':libraryB')
This works fine when creating a release build, but fails for debug ones with the following error:
> Task :app:transformDexArchiveWithDexMergerForDebug FAILED
D8: Program type already present: com.libraryc.SomeClass
It looks like it is fine to bring library project C twice in release because the names get obfuscated separately and there are no conflicts (since I have minifyEnabled true for release builds). However, this doesn't fly in debug.
Since both libraryA and libraryB require a dependency to libraryC, I guess the solution is to keep those dependencies but exclude one of them from the app's app/build.gradle. It's not clear to me how to do this.
I have read on how to exclude modules and groups, but doing something like:
implementation project(':libraryA') {
exclude module: 'libraryC'
}
or
implementation project(':libraryA') {
exclude group: 'com.libraryc'
}
doesn't work, as Gradle doesn't seem to recognize the commands (my guess it's because 'libraryC' is a project, not a module?).

What ended up working was, in the build.gradle of libraryA, using compileOnly for libraryC if on debug mode and compile if in release mode.
My understanding of why this work is the following:
In release mode both versions of libraryC are pulled from the app. Since they are both proguarded (obfuscated) there are no conflicts, as before.
In debug mode only libraryB's version of libraryC is pulled from the app. Since there is no proguarding here, libraryA can use the exported version from libraryB no problem.
In my case I can determine the build type by checking an environment variable which gets manually set as part of the whole build process, so this is what ends up in libraryA's build.gradle:
if(System.getenv('DEBUG_BUILD') != "1") {
compile project(':libraryC')
} else {
compileOnly project(':libraryC')
}
Note that DEBUG_BUILD is an environment variable that I set myself when I launch a debug build, so do not expect this to work by simply copy-pasting into your project.

Related

Android Gradle declare a Variant Build Flavor dependency using API and Exclude in KTS

I'm trying to build a flavor of my app that includes a very heavy dependency and is only going to be used in certain builds for testing and offline development (dependency is Wiremock for Android). However I can't seem to find any flavor variant dependency declarations that also use api() and exclude.
Before I decided to move the dependency to a build variant, I could declare the dependencies like so:
dependencies {
//WireMock - Do not put in release builds bc of large size
api("com.github.tomakehurst:wiremock:2.18.0") {
exclude("org.apache.httpcomponents", "httpclient")
exclude("org.ow2.asm", "asm")
exclude("org.json", "json")
}
api("org.apache.httpcomponents:httpclient-android:4.3.5.1")
}
I would love to restrict this dependency to my build flavor, which I have simply called "mock", something like:
dependencies: {
"mockImplementation"(
api("com.github.tomakehurst:wiremock:2.18.0") {
exclude("org.apache.httpcomponents", "httpclient")
exclude("org.ow2.asm", "asm")
exclude("org.json", "json")
}
api("org.apache.httpcomponents:httpclient-android:4.3.5.1")
})
}
This is obviously very wrong but I am unsure of how to go about formatting with the api and exclude dependency notations as I cannot find very many examples when it comes to also combining these with a build flavor.
After a lot of playing around I ended up with:
// WireMock - Do not put in release builds bc of large size, restrict to mock flavors
"mockImplementation"(mockApi("com.github.tomakehurst:wiremock:2.18.0") {
// Using Android Version Instead
exclude("org.apache.httpcomponents", "httpclient")
//Was getting a classpath conflict for org.objectweb.asm.AnnotationVisitor which is a part of 'net.minidev:asm'
exclude("org.ow2.asm", "asm")
//Was getting this warning, so decided to ignore this version included by WireMock.
//Warning:Dependency org.json:json:20090211 is ignored as it may be conflicting with the internal version provided by Android.
//In case of problem, please repackage with jar to change the class packages
exclude("org.json", "json")
})
"mockImplementation"(mockApi("org.apache.httpcomponents:httpclient-android:4.3.5.1") {})
Note that the "mockApi" was necessary rather than just using "api" to actually constrain the variant.

R8: Program type already present: androidx.databinding.library.baseAdapters.BR

Im getting the above error trying to create a release build of my app. When doing a debug build everything is running fine.
My project has a structure as follows
app (contains databinding)
video sdk (contains data binding)
another sdk (contains data binding)
Im thinking it finds multiple databinding instances which makes the above error but im not really sure how to circumvent this.
What also weird is that the app does compile when clicking run in Android studio but when trying to build from terminal its not compiling
Posting few of workarounds here
./gradlew clean
Exclude duplicates as message Program type already present means there is a naming conflict.
configurations {
compile.exclude group: 'androidx.databinding', module: 'databinding'
}
Then do sync, clean & rebuild.
I am not sure but tried to create a separate module for databinding gradle and add that module into all current modules (app, video sdk, another sdk)
Module core (Gradle with "api"):
api 'com.github.bumptech.glide:glide:4.9.0'
kapt 'com.github.bumptech.glide:compiler:4.9.0'
App module and other SDKs modules will use that core module.
implementation project(path: ':core')
Hope it will help.
I faced this error and spent almost 2 days in figuring out what was causing this error. Eventually, I found out that one of my transitive SDK, which used Kotlin, did not have the following in its Gradle file.
kotlinOptions kotlin_options = {
jvmTarget = "1.8"
}
After adding this, I was able to resolve the error.
Please try this, I am not sure but sometime release apk having problem of conflict ion
Add multiDexEnabled true in app gradle file.
Hope this will help!

Cloud Firestore with gRPC build error

I’m working on an android application, which have to use gRPC and Firestore. However, when I added both one of module from ‘io.grpc’ group dependency (e.g. io.grpc:grpc-okhttp:1.7.0) and firestore dependency (com.google.firebase:firebase-firestore:11.4.2) in the build gradle config, I got a build error “Unable to merge dex”. After with ‘stacktrace’ build option, I saw that the problem is
Multiple dex files define Lio/grpc/internal/OobChannel$5;
It could happen if firestore uses grpc-core module, but there is no one similar in tree dependencies, which I got using [androidDependencies] gradle task. I tried to exclude io.grpc like this:
implementation ('com.google.firebase:firebase-firestore:11.4.2') {
exclude group: 'io.grpc'
}
but there was the same error. Then I thought what if I exclude all ‘io.grpc.’ transitive dependencies from grpc module dependencies with adding grpc-core for internal classes. In this way, I wrote ugly dependencies just for test
implementation 'com.google.firebase:firebase-firestore:11.4.2'
implementation('io.grpc:grpc-okhttp:1.7.0') {
exclude group: 'io.grpc'
}
implementation('io.grpc:grpc-protobuf-lite:1.7.0') {
exclude group: 'io.grpc'
}
implementation('io.grpc:grpc-stub:1.7.0') {
exclude group: 'io.grpc'
}
implementation 'io.grpc:grpc-core:1.7.0'
I was surprised when it successfully compiled, but after launch app, it crashed with java.lang.RuntimeException: Internal error in Firestore (0.6.6-dev)
Caused by: java.lang.NoSuchMethodError: No static method zzcyc()Lio/grpc/ManagedChannelProvider; in class Lio/grpc/ManagedChannelProvider; or its super classes (declaration of 'io.grpc.ManagedChannelProvider' appears in /data/app/com.zipr.test-2/split_lib_dependencies_apk.apk)
I use gradle 3.0.0-rc1 with enabling multidex support. I deleted .gradle, build directories, cleaned rebuilt project, but I still have build error. What can I do to resolve this problem?
Due to a variety of factors that constrain the way we build Android SDKs at Google, Firestore proguards a copy of gRPC within itself. Unfortunately this is leaky and you're running into the fallout: the 11.4.2 Firestore SDK is incompatible with any external gRPC :-(.
This is essentially our top issue for the Firestore Android SDK and I'm sorry you've run into it.

How can I find the dependencies in my app that are using findbugs? (findbugs conflict)

I'm trying to discover the specific conflict when adding espresso to my app's gradle file:
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.1') {
exclude group: 'com.android.support', module: 'support-annotations'
}
Android Studio states "Warning:Conflict with dependency 'com.google.code.findbugs:jsr305'.
Dependency conflict error in my Android app which has Android Tests states the error means the dependency I am using in my app is version 3.0.0 while the one in my test app is 2.0.1.
However, my gradle never explicitly adds "com.google.code.findbugs", indicating it was part of another dependency I added to my "compile" and "androidTestCompile" statements. How do I find the dependencies in my app that are using findbugs?
Check your dependencies:
HelloApp/
app/
- build.gradle // local gradle config (for app only)
...
- build.gradle // global gradle config (for whole project)
- settings.gradle
- gradle.properties
Check here:
dependencies {
compile project(':libraries:lib')
}
Later check this LINK you have Unit testing support orientation
Execute the following command:
./gradlew app:dependencies
This will print a (large) graph of dependencies.
For the meaning of the arrows and stars, please refer to this SO answer.

Android Studio: Duplicate files copied in APK META-INF/DEPENDENCIES when compile

I exported my project from Eclipse and imported to Android Studio using the instructions in this link: http://developer.android.com/sdk/installing/migrate.html
When I build, I have an error:
Duplicate files copied in APK META-INF/DEPENDENCIES
After searching, I found a solution: add
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
}
into build.gradle. And it works!
But I don't understand why I had this error and why I've had to apply that fix. Can anybody explain?
While Scott Barta's answer is correct, is lacks a simple and common solution: just add
android {
packagingOptions {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/NOTICE'
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/NOTICE.txt'
}
}
to your build.gradle to ignore those duplicates.
In Android Gradle builds, you're not permitted to include the same file with the same path more than once in the output. In your build, there were two META-INF/DEPENDENCIES files coming from different places. Since you don't need this file at all in your application, the simplest thing to do is to tell the build system to ignore it altogether, which is what this exclude directive does.
There's also a pickFirst directive to tell the build system to keep one of the copies; there's a tiny amount of detail on that in Android Gradle plugin 0.7.0: "duplicate files during packaging of APK".
Android builds in Gradle are rather strict about duplicate files, which can make life difficult. There's a similar problem if you include the same Java class more than once, where you get the "Multiple dex files define" error (see Multiple dex files define Landroid/support/v4/accessibilityservice/AccessibilityServiceInfoCompat) for a typical example).
Other build systems are more lenient. It's typical in Java that if you include the same class more than once in a classpath, for example, the first copy it sees is the one that's used; duplicates after that are ignored. This is in most cases easier to deal with, but it has a couple problems. The biggest one is that there can be subtle errors if multiple different versions of a file creep into the build without you knowing -- it can be difficult to figure out what's going on. When you do figure it out, you can usually solve it by juggling the order in which things are included to make sure the one you want makes it to the final output, but in very complex builds, this can be difficult to achieve, and it can happen that doing seemingly unrelated things like including new libraries in your project can upset the ordering and lead to a lot of woe.
For that reason, Gradle has the philosophy of not relying on ordering of things to determine "winners" in the game of resolving duplicates, and it forces the developer to make all dependencies explicit. Android's implementation of its build system on top of Gradle follows that philosophy.
The simplest solution is to add
packagingOptions {
pickFirst 'META-INF/*'
}
to your build.gradle in android section
The easiest way I've found to resolve this problem is to use a wildcard, so you don't find yourself having to manually declare each file in conflict.
packagingOptions {
pickFirst '**'
}
In case that anyone having these problem while uploading new .apk to Google Play Store, after updatng Android Studio ;
click V1 Jar Signature not Full Apk Signature while Generating new Apk with old Keystore
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.google.android.gms:play-services-ads:10.2.1'
implementation 'com.android.support:support-annotations:25.0.1'
testImplementation 'junit:junit:4.12'
**// select only one in two line below** implementation ‘package’ //implementation project(‘:package’)
}
// good luck

Categories

Resources