Gradle configuration inheritance - android

I have multiple dependencies inside a gradle file and I introduced a new build variant call "apple". But I don't want to copy and paste as the following.
dependencies {
debugCompile "com.android:libraryA:1.0.0"
debugCompile "com.android:libraryB:1.0.0"
debugCompile "com.android:libraryC:1.0.0"
appleCompile "com.android:libraryA:1.0.0"
appleCompile "com.android:libraryB:1.0.0"
appleCompile "com.android:libraryC:1.0.0"
}
Is there a way I can say appleCompile depends on debugCompile?

You can declare a new configuration:
configurations {
[debugCompile, appleCompile].each { it.extendsFrom commonCompile }
}
Now commonCompile configuration will apply dependencies for both debug and apple configurations, so you don't need to specify those twice.
dependencies {
commonCompile "com.android:libraryA:1.0.0"
commonCompile "com.android:libraryB:1.0.0"
commonCompile "com.android:libraryC:1.0.0"
}

Related

How to add dependency for two build types with one configuration?

My app consists of 2 flavors and 3 build types:
productFlavors {
free
paid
}
buildTypes {
debug
beta
release
}
I can simply add a dependency for all variants, specific flavor or build type:
dependencies {
implementation "some-dependency"
freeImplementation "some-dependency"
betaImplementation "some-dependency"
}
To add a dependency for a specific variant, I can do do this:
configurations {
freeDebugImplementation
}
dependencies {
freeDebugImplementation "some-dependency"
}
But what I want is to combine several flavors/build types/variants. Something along the lines of:
configurations {
debugBetaImplementation
}
dependencies {
debugBetaImplementation "some-dependency"
}
which should be equivalent to:
dependencies {
debugImplementation "some-dependency"
betaImplementation "some-dependency"
}
Is there a way to achieve this?

Use module's packackingOptions when importing module with gradle

I want to include a module A into Module B.
Module A's build.gradle includes packackingOptions that need to be executed.
These packackingOptions are executed when I build module A. They are not executed when I build module B, which imports module A.
How can I make sure that the packackingOptions from module A's build.gradle are also executed when importing module A into module B?
Module B's build.gradle looks like this:
dependencies {
implementation project(':A')
}
Module A's build.gradle looks like this:
android {
packagingOptions {
pickFirst 'assets/**'
}
}
I set up the project structure as follows:
buildscript-test-app
|
|
buildscript-test-lib
| \------------------------\
| |
buildscript-test-lib-sub-a buildscript-test-lib-sub-b
Both lib-sub-* contain assets/foo.txt with different contents.
build.gradle of buildscript-test-lib:
apply plugin: 'com.android.library'
android {
// omitted default config stuff
packagingOptions {
pickFirst 'assets/**'
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':buildscript-test-lib-sub-a')
implementation project(':buildscript-test-lib-sub-b')
}
build.gradle of buildscript-test-app:
apply plugin: 'com.android.application'
android {
// omitted default config stuff
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':buildscript-test-lib')
}
Gradle always picks the file from buildscript-test-lib-sub-a regardless of the order of dependencies (presumably because of alphabetic ordering).
Something else in your buildscript must be wrong if this doesn't work. If it doesn't work, can you provide more details on the build.gradle of your app module and library modules?
Maybe you are overriding pickFirsts in your app. If that's the case, you should instead of pickFirsts = [somevalue] do pickFirst += 'foo' or pickFirst = 'foo'

Android Studio 3.0 Error. Migrate dependency configurations for local modules

I recently installed the latest Canary build of Android Studio which is currently using the Android Gradle plugin 3.0.0-alpha4 .
I now get a error:
Error:Failed to resolve: Could not resolve project :MyLib.
Required by:
project :app
I has read: Migrate dependency configurations for local modules
dependencies
{
// This is the old method and no longer works for local
// library modules:
// debugCompile project(path: ':foo', configuration: 'debug')
// releaseCompile project(path: ':foo', configuration: 'release')
// Instead, simply use the following to take advantage of
// variant-aware dependency resolution. You can learn more about
// the 'implementation' configuration in the section about
// new dependency configurations.
implementation project(':foo')
// You can, however, keep using variant-specific configurations when
// targeting external dependencies. The following line adds 'app-magic'
// as a dependency to only the 'debug' version of your module.
debugImplementation 'com.example.android:app-magic:12.3'
}
I changed:
releaseCompile project(path: ':MyLib', configuration: 'appReleaseApp')
debugCompile project(path: ':MyLib', configuration: 'appDebug')
to:
implementation project(':MyLib')
but i still have this error: Error:Failed to resolve: Could not resolve project :MyLib.
lib gradle:
apply plugin: 'com.android.library'
android {
publishNonDefault true
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
minSdkVersion 14
targetSdkVersion 25
}
buildTypes {
debug {
...
}
releaseApp {
...
}
releaseSdk {
...'
}
}
flavorDimensions "default"
productFlavors {
flavor1{
...
flavor2{
...
}
flavor3{
...
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:support-v4:25.3.1'
compile 'com.google.code.gson:gson:2.8.0'
compile 'com.google.android.gms:play-services-maps:10.2.6'
compile 'com.google.android.gms:play-services-gcm:10.2.6'
compile 'com.google.android.gms:play-services-location:10.2.6'
}
apply plugin: 'maven'
uploadArchives {
repositories {
mavenDeployer {
repository(url: mavenLocal().url)
}
}
}
app gradle:
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
vectorDrawables.useSupportLibrary = true
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
minSdkVersion 19
targetSdkVersion 25
versionCode 12
versionName "5.0.2"
}
buildTypes {
release {
...
}
debug {
...
}
}
flavorDimensions "default"
productFlavors {
flavor1 {
...
}
flavor2 {
...
}
}
testOptions {
unitTests {
all {
jvmArgs '-noverify'
systemProperty 'robolectric.logging.enable', true
}
}
}
}
repositories {
flatDir {
dirs 'libs'
}
}
dependencies {
// releaseCompile project(path: ':MyLib', configuration: 'appRelease')
// debugCompile project(path: ':MyLib', configuration: 'appDebug')
implementation project(':MyLib')
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.google.android.gms:play-services-maps:10.2.6'
compile 'com.google.android.gms:play-services-location:10.2.6'
compile 'com.google.android.gms:play-services-analytics:10.2.6'
compile 'com.google.android.gms:play-services-gcm:10.2.6'
compile 'com.google.code.gson:gson:2.8.0'
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:design:25.3.1'
compile 'com.android.support:support-v4:25.3.1'
compile 'com.android.support:cardview-v7:25.3.1'
compile 'com.android.support:gridlayout-v7:25.3.1'
compile 'com.android.volley:volley:1.0.0'
compile 'com.facebook.stetho:stetho:1.4.1'
compile 'com.facebook.stetho:stetho-okhttp3:1.4.1'
compile 'com.android.support:percent:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.squareup.picasso:picasso:2.5.2'
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:2.1.0'
testCompile 'org.robolectric:robolectric:3.1.4'
testCompile 'org.assertj:assertj-core:1.7.1'
compile 'com.flipboard:bottomsheet-core:1.5.0'
compile 'com.flipboard:bottomsheet-commons:1.5.0'
compile 'com.android.support.constraint:constraint-layout:1.0.1'
}
apply plugin: 'com.google.gms.google-services'
Please help
Google added more instruction how to solve it: Resolve build errors related to dependency matching
Cause of build error:
Your app includes a build type that a library dependency does not.
For example, your app includes a "staging" build type, but a
dependency includes only a "debug" and "release" build type.
Note that there is no issue when a library dependency includes a build
type that your app does not. That's because the plugin simply never
requests that build type from the dependency.
Resolution
Use matchingFallbacks to specify alternative matches for a given build type, as shown below:
// In the app's build.gradle file.
android {
buildTypes {
debug {}
release {}
staging {
// Specifies a sorted list of fallback build types that the
// plugin should try to use when a dependency does not include a
// "staging" build type. You may specify as many fallbacks as you
// like, and the plugin selects the first build type that's
// available in the dependency.
matchingFallbacks = ['debug', 'qa', 'release']
}
}
}
After facing the same issue, I finally declared exactly the same buildTypes in both App and Modules' build.gradle files.
In your case, adding
buildTypes {
debug {}
releaseApp {}
releaseSdk {}
}
to your module's build.gradle should do the trick.
Be sure to change any "compile project" to "implementation project" too.
Hope it helps
With the new plugin, the variant-aware dependency resolution
implementation project(':MyLib')
needs to have exact matching build types. The migration guide describes this
For instance, it is not possible to make a 'debug' variant consume a
'release' variant through this mechanism because the producer and
consumer would not match. (In this case, the name 'debug' refers to
the published configuration object mentioned above in the Publishing
Dependencies section.) Now that we publish two configurations, one for
compiling and one for runtime, this old way of selecting one
configuration really doesn't work anymore.
So the old method of
releaseCompile project(path: ':foo', configuration: 'debug')
will not work anymore.
Example
With your example this would look like this:
In app build.gradle:
apply plugin: 'com.android.application'
android {
buildTypes {
debug {}
releaseApp {}
releaseSdk {}
}
...
dependencies {
implementation project(':MyLib')
}
}
In module/lib 'MyLib' build.gradle:
apply plugin: 'com.android.library'
android {
buildTypes {
debug {}
releaseApp {}
releaseSdk {}
}
}
Therefore the build type must exactly match, no more no less.
Using Build-Type Fallbacks
A new feature called "matchingFallbacks" can be used to define default buildtypes if a sub-module does not define the buildtype.
Use matchingFallbacks to specify alternative matches for a given build type (...)
For example if module/lib 'MyLib' gradle would look like this:
apply plugin: 'com.android.library'
android {
buildTypes {
debug {}
releaseLib {}
}
}
You could define the following in your app build.gradle:
apply plugin: 'com.android.application'
android {
buildTypes {
debug {}
releaseApp {
...
matchingFallbacks = ['releaseLib']
}
releaseSdk {
...
matchingFallbacks = ['releaseLib']
}
}
...
dependencies {
implementation project(':MyLib')
}
}
Missing Flavor Dimensions
Use missingDimensionStrategy in the defaultConfig block to specify the
default flavor the plugin should select from each missing dimension
android {
defaultConfig {
missingDimensionStrategy 'minApi', 'minApi18', 'minApi23'
...
}
}
I was facing the same problem, I found this migration page:
Build matching types
It states:
Select defaults for missing build types
If a consumer configures a build type that a producer does not, you need to manually match the consumer's build type to one from the producer. For example, if your app module configures a "staging" build type and its library module dependency, "mylibrary", does not, the Android plugin throws the following build error:
Error:Failed to resolve: Could not resolve project :mylibrary.
Required by: project :app
To resolve this error, you need to specify which build type from "mylibrary" the Android plugin should match to the app's "staging" build type. You can do this with the buildTypeMatching property in the app's build.gradle file, as shown below:
// Add the following to the consumer's build.gradle file.
android {
...
// Tells the Android plugin to use a library's 'debug' build type
// when a 'staging' build type is not available. You can include
// additional build types, and the plugin matches 'staging' to the
// first build type it finds from the one's you specify. That is,
// if 'mylibrary' doesn't include a 'debug' build type either, the
// plugin matches 'staging' with the producer's 'release' build type.
buildTypeMatching 'staging', 'debug', 'release'
}
Adding buildTypeMatching fixed it for me without creating unecessary types in my library
Today I also had the same problem after migrating to Android Studio 3.
The problem is the gradle is not able to resolve the certain libraries due to network issue. The reasons might be various.
If you work behind the proxy you need to add the proxy parameters in gradle.properties file:
systemProp.http.proxyHost=<proxy_host>
systemProp.http.proxyPort=<proxy_port
systemProp.https.proxyHost=<proxy_host>
systemProp.https.proxyPort=<proxy_port>
In my case I had one more issue. My company uses the self signed SSL certificate so the SSL connection had some problem. If same applies also for you, you can set the parameter again in gradle.properties file as follows:
org.gradle.jvmargs=-Djavax.net.ssl.trustStore="/usr/lib/jvm/java-8-oracle/jre/lib/security/cacerts" -Djavax.net.ssl.trustStoreType=JKS -Djavax.net.ssl.keyStorePassword=changeit
To be more clear you can click on "Show details" link in messages log in Android Studio. This log will be more helpful to decide what is the real problem.
This solution worked for me. I'm using Android Studio 3.1.2. Android Gradle plugin 3.1.2. Gradle 4.4. I have a library module with flavours such as trial and premium. As part of the process of migrating to the Android Gradle plugin 3.1.2 I added a flavour dimension of main to my library module's gradle build file. To correct the build error therefore in my app's build.gradle file I changed the following:
debugImplementation project(path: ':library', configuration: 'premiumDebug')
releaseImplementation project(path: ':library', configuration: 'premiumRelease')
became
implementation project(':library')
and I added the following line to my defaultConfig block: missingDimensionStrategy 'main', 'premium'

Defining dependencies for multiple variants

Say we have four build types: debug, qa, beta, and release.
We can define dependencies for specific variants like so:
dependencies {
// These dependencies are only included for debug and qa builds
debugCompile 'com.example:lib:1.0.0'
qaCompile 'com.example:lib:1.0.0'
}
Is there a way to compile these dependencies for multiple variants without repeating the artifact descriptor?
For example, I would like to do something like this:
dependencies {
internalCompile 'com.example:lib:1.0.0'
}
Where internalCompile would specify that the library is included for both debug and qa builds.
I believe that the solution lies within defining a new Gradle configuration, but if I create an internalCompile configuration I am unsure how to ensure that those dependencies are only compiled for qa and debug builds.
extendsFrom
The names of the configurations which this configuration extends from. The artifacts of the super configurations are also available in this configuration.
configurations {
// debugCompile and qaCompile are already created by the Android Plugin
internalCompile
}
debugCompile.extendsFrom(internalCompile)
qaCompile.extendsFrom(internalCompile)
dependencies {
//this adds lib to both debugCompile and qaCompile
internalCompile 'com.example:lib:1.0.0'
}
Alternatively:
You can create a collection of artifact descriptors and use it with multiple configurations.
List internalCompile = ["com.example:lib:1.0.0",
"commons-cli:commons-cli:1.0#jar",
"org.apache.ant:ant:1.9.4#jar"]
List somethingElse = ['org.hibernate:hibernate:3.0.5#jar',
'somegroup:someorg:1.0#jar']
dependencies {
debugCompile internalCompile
qaCompile internalCompile, somethingElse
}

Multi flavor app based on multi flavor library in Android Gradle

My app has several flavors for several markets in-app-billing systems.
I have a single library which shares the base code for all of my projects. So I decided to add those payment systems to this library as product flavors.
The question is can android library have product flavors?
If so, how can I include different flavors in respective flavor of the app?
I searched a lot, and I couldn't find anything about this scenario. The only close thing I found was this in http://tools.android.com/tech-docs/new-build-system/user-guide:
dependencies {
flavor1Compile project(path: ':lib1', configuration: 'flavor1Release')
flavor2Compile project(path: ':lib1', configuration: 'flavor2Release')
}
I changed configuration to different things but it did not work!
I'm using android studio 0.8.2.
Finally I found out how to do this, I will explain it here for others facing same problem:
If App and Library have same Flavor name(s)
It's possible since Gradle Plugin 3.0.0 (and later) to do something like:
Library build.gradle:
apply plugin: 'com.android.library'
// Change below's relative-path
// (as the `../` part is based on my project structure,
// and may not work for your project).
apply from: '../my-flavors.gradle'
dependencies {
// ...
}
android {
// ...
}
Project build.gradle:
buildscript {
// ...
}
apply plugin: 'com.android.application'
// Note that below can be put after `dependencies`
// (I just like to have all apply beside each other).
apply from: './my-flavors.gradle'
dependencies {
api project(':lib')
}
android {
productFlavors {
// Optionally, configure each flavor.
market1 {
applicationIdSuffix '.my-market1-id'
}
market2 {
applicationIdSuffix '.my-market2-id'
}
}
}
My flavors .gradle:
android {
flavorDimensions 'my-dimension'
productFlavors {
market1 {
dimension 'my-dimension'
}
market2 {
dimension 'my-dimension'
}
}
}
If App or Library has different Flavor-name (old answer)
The key part is to set publishNonDefault to true in library build.gradle, Then you must define dependencies as suggested by user guide.
Update 2022; publishNonDefault is now by default true, and setting it to false is ignored, since said option is deprecated.
The whole project would be like this:
Library build.gradle:
apply plugin: 'com.android.library'
android {
....
publishNonDefault true
productFlavors {
market1 {}
market2 {}
market3 {}
}
}
project build.gradle:
apply plugin: 'com.android.application'
android {
....
productFlavors {
market1 {}
market2 {}
market3 {}
}
}
dependencies {
....
market1Compile project(path: ':lib', configuration: 'market1Release')
market2Compile project(path: ':lib', configuration: 'market2Release')
// Or with debug-build type support.
android.buildTypes.each { type ->
market3Compile project(path: ':lib', configuration: "market3${type.name}")
}
}
Now you can select the app flavor and Build Variants panel and the library will be selected accordingly and all build and run will be done based on the selected flavor.
If you have multiple app module based on the library Android Studio will complain about Variant selection conflict, It's ok, just ignore it.
There are one problem with Ali answer. We are losing one very important dimension in our build variants. If we want to have all options (in my example below 4 (2 x 2)) we just have to add custom configurations in main module build.gradle file to be able to use all multi-flavor multi-buildType in Build Variants. We also have to set publishNonDefault true in the library module build.gradle file.
Example solution:
Lib build.gradle
android {
publishNonDefault true
buildTypes {
release {
}
debug {
}
}
productFlavors {
free {
}
paid {
}
}
}
App build.gradle
android {
buildTypes {
debug {
}
release {
}
}
productFlavors {
free {
}
paid {
}
}
}
configurations {
freeDebugCompile
paidDebugCompile
freeReleaseCompile
paidReleaseCompile
}
dependencies {
freeDebugCompile project(path: ':lib', configuration: 'freeDebug')
paidDebugCompile project(path: ':lib', configuration: 'paidDebug')
freeReleaseCompile project(path: ':lib', configuration: 'freeRelease')
paidReleaseCompile project(path: ':lib', configuration: 'paidRelease')
}
Update for Android Plugin 3.0.0 and higher
According to the official Android Documentation - Migrate dependency configurations for local modules,
With variant-aware dependency resolution, you no longer need to use variant-specific configurations, such as freeDebugImplementation, for local module dependencies—the plugin takes care of this for you
You should instead configure your dependencies as follows:
dependencies {
// This is the old method and no longer works for local
// library modules:
// debugImplementation project(path: ':library', configuration: 'debug')
// releaseImplementation project(path: ':library', configuration: 'release')
// Instead, simply use the following to take advantage of
// variant-aware dependency resolution. You can learn more about
// the 'implementation' configuration in the section about
// new dependency configurations.
implementation project(':library')
// You can, however, keep using variant-specific configurations when
// targeting external dependencies. The following line adds 'app-magic'
// as a dependency to only the "debug" version of your module.
debugImplementation 'com.example.android:app-magic:12.3'
}
So in Ali's answer, change
dependencies {
....
market1Compile project(path: ':lib', configuration: 'market1Release')
market2Compile project(path: ':lib', configuration: 'market2Release')
}
to
implementation project(':lib')
And plugin will take care of variant specific configurations automatically. Hope it helps to others upgrading Android Studio Plugin to 3.0.0 and higher.
My Android Plugin is 3.4.0,and I find that it doesn't need configurations now.All you need is to make sure the flavorDimensions and productFlavors in application contains one productFlavor of the same flavorDimensions and productFlavors in libraries.For sample:
In mylibrary's build.gradle
apply plugin: 'com.android.library'
android {
....
flavorDimensions "mylibFlavor"
productFlavors {
market1
market2
}
}
application's build.gradle:
apply plugin: 'com.android.application'
android {
....
flavorDimensions "mylibFlavor", "appFlavor"
productFlavors {
market1 {
dimension "mylibFlavor"
}
market2 {
dimension "mylibFlavor"
}
common1 {
dimension "appFlavor"
}
common2 {
dimension "appFlavor"
}
}
}
dependencies {
....
implementation project(path: ':mylibrary')
}
After sync,you can switch all options in Build Variants Window:
To get the flavors working on an AAR library, you need to define defaultPublishConfig in the build.gradle file of your Android Library module.
For more information, see: Library Publication.
Library Publication
By default a library only publishes its release variant. This variant
will be used by all projects referencing the library, no matter which
variant they build themselves. This is a temporary limitation due to
Gradle limitations that we are working towards removing. You can
control which variant gets published:
android {
defaultPublishConfig "debug" }
Note that this publishing configuration name references the full
variant name. Release and debug are only applicable when there are no
flavors. If you wanted to change the default published variant while
using flavors, you would write:
android {
defaultPublishConfig "flavor1Debug" }
I also ran into a problem compiling modules for various options.
What i've found:
It looks like we don't need add publishNonDefault true into lib's build.gradle file, since Gradle 3.0.1.
After decompiling a class BaseExtension found this:
public void setPublishNonDefault(boolean publishNonDefault) {
this.logger.warn("publishNonDefault is deprecated and has no effect anymore. All variants are now published.");
}
And instead of:
dependencies {
...
Compile project(path: ':lib', configuration: 'config1Debug')
}
We should use:
dependencies {
...
implementation project(':lib')
}
Only the important thing, is to add a configurations {...} part to the build.gradle.
So, the final variant of app's build.gradle file is:
buildTypes {
debug {
...
}
release {
...
}
}
flavorDimensions "productType", "serverType"
productFlavors {
Free {
dimension "productType"
...
}
Paid {
dimension "productType"
...
}
Test {
dimension "serverType"
...
}
Prod {
dimension "serverType"
...
}
}
configurations {
FreeTestDebug
FreeTestRelease
FreeProdDebug
FreeProdRelease
PaidTestDebug
PaidTestRelease
PaidProdDebug
PaidProdRelease
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation project(':lib')
...
}
Also, you can use Filter variants to restrict build variants.
P.s. don't forget to include modules in the settings.gradle file, like:
include ':app'
include ':lib'
project(':lib').projectDir = new File('app/libs/lib')
At the moment it's not possible, although if I recall correctly its a feature they want to add. (Edit 2: link, link2 )
Edit:
For the moment I'm using the defaultPublishConfig option to declare which library variant get's published:
android {
defaultPublishConfig fullRelease
defaultPublishConfig demoRelease
}
I know this subject has been closed, but just an update with gradle 3.0, see this : https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#variant_aware and grep matchingFallbacks and missingDimensionStrategy.
Now it's way more simple to declare the dependencies between module flavors.
...and in this precise case with gradle3.0, as flavors share the same name, gradle would map them magically, there is no configuration required.
In this situation. How could I import the dependency for a specific build. For example: market1Common1Debug
market1Common1DebugImplementation 'androidx.appcompat:1.2.0'

Categories

Resources