如何将build.gradle逻辑拆分为更多.gradle文件?

Ser*_*kyi 6 android gradle build.gradle android-gradle-plugin

我有一个长build.gradle文件,它有我想要移动到单独.gradle文件中的函数以保持逻辑清洁.文档建议在这种情况下使用外部构建脚本.我在build.gradle文件中有下一个功能:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

代码逻辑并不重要,它放在build.gradle文件时工作正常.但是当我将此方法移动到外部文件并将其包含在以下内容时失败:

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

我有下一个错误:

Cannot cast object 'DefaultSigningConfig{..}' with class
com.android.builder.signing.DefaultSigningConfig' to class 
'com.android.builder.model.SigningConfig'
Run Code Online (Sandbox Code Playgroud)

基本上它说它无法将实现强制转换为接口.因为DefaultSigningConfig实现了SigningConfig,请参见此处.这是没有意义的,直到我看到下一个答案.

两个类被视为完全不同的类,即使它们在由不同的类加载器加载时具有相同的包和名称(甚至是实现/字段/方法).使用插件或外部构建脚本时就是这种情况.

但是,如何将方法从build.gradle模块化的单独文件中分离出来?

Ser*_*kyi 0

我发现(谢谢,开源!)android 插件 DSL api 是不一致的,让 setter 采用SigningConfig接口,但强制 getter 强制转换为internal.dsl.SigningConfig类。

所以它应该是这样的:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但随后BuiltTypeDSL强制转换为SigningConfigDSL类:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,这两种方法的getSigningConfig()返回类型具有相同的名称SigningConfig但不同的包名。一个是接口com.android.builder.model.SigningConfig,另一个是com.android.build.gradle.internal.dsl.SigningConfig扩展了com.android.builder.signing.DefaultSigningConfig实现的类com.android.builder.model.SigningConfig,这就是我的代码停止工作的地方,因为由于 OOP 原则,我们可以转换DefaultSigningConfigSigningConfig接口,但不能将其转换为internal.dsl.SigningConfig类。

为了使代码正常工作,我们可以创建internal.dsl.SigningConfig而不是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
Run Code Online (Sandbox Code Playgroud)

DefaultSigningConfig用内部 dsl 模型包装:

android{
  signingConfigs {
      debug {
          initWith loadFromPropertiesFile("DEBUG_KEY_PROPERTIES")
      }
  }

  buildTypes {
    debug {
        signingConfig signingConfigs.debug
    }
  }
}
Run Code Online (Sandbox Code Playgroud)