How to break build.gradle logic into more .gradle files?

I have a long build.gradle file that has functions that I want to move to a separate .gradle file in order to keep the logic clean. Documents suggest using external build scripts for this case. I have the following function in the build.gradle file:

 android{ buildTypes { debug { signingConfig = loadFromPropertiesFile("DEBUG_KEY_PROPERTIES") } } } import com.android.builder.signing.DefaultSigningConfig import com.android.builder.model.SigningConfig SigningConfig loadFromPropertiesFile(keyProperty) { // Load signing config from singning properties file println keyProperty println ("${keyProperty}") if (project.hasProperty(keyProperty)) { File releasePropsFile = new File(project.property(keyProperty)) println("Loading config from properties file: ${releasePropsFile}") if (releasePropsFile.exists()) { Properties releaseProps = new Properties() releaseProps.load(new FileInputStream(releasePropsFile)) println releaseProps def signingConfig = new DefaultSigningConfig(keyProperty) signingConfig.storeFile = file(releasePropsFile.getParent() + "/" + releaseProps['keystore.file']) signingConfig.storePassword = releaseProps['keystore.password'] //signingConfig.storeType = 'PKCS12' signingConfig.keyAlias = releaseProps['alias.name'] signingConfig.keyPassword = releaseProps['alias.password'] return signingConfig } else { println("Can't read configuration file: ${releasePropsFile}") return null } } else { println("Project has not define configuration file: ${keyProperty}") return null } } 

The logic of the code does not matter, it works fine when it is placed in the build.gradle file. But this fails when I move this method to an external file and include it with:

apply from: "$rootDir/gradle/android-signing.gradle"

I got the following error:

 Cannot cast object 'DefaultSigningConfig{..}' with class com.android.builder.signing.DefaultSigningConfig' to class 'com.android.builder.model.SigningConfig' 

Basically, this suggests that he cannot implement the implementation of the interface. For DefaultSigningConfig implements SigningConfig see here . This does not make sense until I see the following answer .

Two classes are considered as completely different classes, even if they have the same package and name (and even implementation / fields / methods) when loaded by different class loaders. In this case, you are using a plugin or an external build script.

But then, how can I split the methods from build.gradle into modular separate files?

+6
source share
1 answer

I found (thanks, opensource!) That the Android-DSL api plugin is incompatible, allowing the setter to use the SigningConfig interface, but forcing getter to use the internal.dsl.SigningConfig class.

So it should be like this:

 package com.android.builder.core; import com.android.builder.internal.BaseConfigImpl; import com.android.builder.model.BuildType; import com.android.builder.model.SigningConfig; public class DefaultBuildType extends BaseConfigImpl implements BuildType { ... public BuildType setSigningConfig(SigningConfig signingConfig) { mSigningConfig = signingConfig; return this; } @Override public SigningConfig getSigningConfig() { return mSigningConfig; } } 

But then, the value of BuiltTypeDSL is forcibly applied to the SigningConfigDSL class:

 package com.android.build.gradle.internal.dsl import com.android.builder.core.DefaultBuildType /** * DSL object to configure build types. */ public class BuildType extends DefaultBuildType implements Serializable { ... /** The signing configuration. */ @Override SigningConfig getSigningConfig() { return (SigningConfig) super.signingConfig } } 

Note that both getSigningConfig() methods have a return type with the same SigningConfig name, but different packagename. One of them is the com.android.builder.model.SigningConfig interface, and the other is the com.android.build.gradle.internal.dsl.SigningConfig class, which extends com.android.builder.signing.DefaultSigningConfig , which implements com.android.builder.model.SigningConfig and that when my code stops working, because due to the principles of OOP, we can use DefaultSigningConfig for the SigningConfig interface but cannot pass it to the internal.dsl.SigningConfig class.

To make the code work, we can either create internal.dsl.SigningConfig instead of DefaultSigningConfig :

 import com.android.build.gradle.internal.dsl.SigningConfig def signingConfig = new SigningConfig(keyProperty) // note that this is class which extends DefaultSigningConfig, not interface signingConfig.storeFile = ... // same as before signingConfig.storePassword = ... signingConfig.keyAlias = ... signingConfig.keyPassword = ... return signingConfig 

or wrap DefaultSigningConfig with internal dsl model:

 android{ signingConfigs { debug { initWith loadFromPropertiesFile("DEBUG_KEY_PROPERTIES") } } buildTypes { debug { signingConfig signingConfigs.debug } } } 
0
source

Source: https://habr.com/ru/post/978080/


All Articles