Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android project - can I override the signingConfigs set in build.gradle using an init.gradle init script?

In a CI server I would like to get rid of the signingConfigs the developers have set in the file build.gradle for an Android project:

build.gradle

buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
    }
}
apply plugin: 'com.android.application'

dependencies {
    compile fileTree(include: '*.jar', dir: 'libs')
}

android {
    signingConfigs {
        releaseConfig {
            keyAlias 'fake_key_alias'
            keyPassword 'fake_key_pass'
            storeFile file('C:/fake')
            storePassword 'fake_store_pass'
        }
    } 

    compileSdkVersion 25
    buildToolsVersion "25.0.0"

    defaultConfig {
        minSdkVersion 20
        targetSdkVersion 25
    }

    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
            aidl.srcDirs = ['src']
            renderscript.srcDirs = ['src']
            res.srcDirs = ['res']
            assets.srcDirs = ['assets']
        }

        // Move the tests to tests/java, tests/res, etc...
        instrumentTest.setRoot('tests')

        // Move the build types to build-types/<type>
        // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
        // This moves them out of them default location under src/<type>/... which would
        // conflict with src/ being used by the main source set.
        // Adding new build types or product flavors should be accompanied
        // by a similar customization.
        debug.setRoot('build-types/debug')
        release.setRoot('build-types/release')
    }
    buildTypes {
        release {
            zipAlignEnabled true
            signingConfig signingConfigs.releaseConfig
        }
    }
}

Then, I would like to replace them with a signingConfig written in an init.gradle init script placed in the CI server. I would like to use the same technique showed here (Gradle Init script plugins) to replace the repositories but I'm not able to reference the signingConfigs.

init.gradle

apply plugin:EnterpriseSigningConfigPlugin

class EnterpriseSigningConfigPlugin implements Plugin<Gradle> {

    void apply(Gradle gradle) {

        gradle.allprojects{ project ->
            project.android.signingConfigs {

                // Remove all signingConfigs
                all {SigningConfig cfg ->
                        remove cfg
                }

                // add the signingConfig
                signingConfigs {
                        releaseConfig {
                            keyAlias 'CI_key_alias'
                            keyPassword 'CI_key_pass'
                            storeFile file('/CI_storeFile')
                            storePassword 'CI_store_pass'
                        }

                }
            }
        }
    }
}

When I execute the command gradle -I init.gradle clean assembleRelease, I get the following error:

FAILURE: Build failed with an exception.

* Where:
Initialization script 'C:\Users\it056548\.init\init.gradle' line: 11

* What went wrong:
Could not compile initialization script 'C:\Users\it056548\.init\init.gradle'.
> startup failed:
  initialization script 'C:\Users\it056548\.init\init.gradle': 11: unable to resolve class SigningConfig
   @ line 11, column 21.
                     all {SigningConfig cfg ->
                         ^

  1 error


* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 3.721 secs

How should I reference the signingConfigs? Is it feasible? Is this a valid approach to address my need? Thanks in advance for the help!

like image 541
Quake Avatar asked Sep 05 '25 18:09

Quake


1 Answers

To solve this problem I had to take into account that the Gradle build lifecycle happens in three phases: initialization, configuration, and execution. Overriding the signingConfig assigned to the release buildType must occur at the end of the configuration phase, meaning after the build has evaluated all the project(s) properties and tasks and they're still available for modification.

Gradle offers the project hook project.afterEvaluate() that allows executing a block of code at the end of the configuration phase, where all the project(s) properties and tasks have already been set and they are still available for modification before the execution phase starts.

The use of this hook comes at handy in an initialization script, such as the following:

init.gradle

// Enter the scope of the root project
rootProject{

    println ""
    println "Project name: ${project.name}"
    println ""

    // Apply the subsequent code after the configuration phase has finished
    afterEvaluate{

        //Check if it exixts the properties file for the signing configuration specified in gradle.properties by the property helloWorldAppSigningProperties.
        //Then read the signing configuration properties
        //If something goes wrong an exception is thrown and the build execution is terminated
        if (new File(helloWorldAppSigningProperties).exists()){ 
            println ""
            println "Found properties file: ${helloWorldAppSigningProperties}!"

            def signingProps = new Properties()
            file(helloWorldAppSigningProperties).withInputStream{signingProps.load(it)}

            ext{
                ka = signingProps.getProperty("keyAlias")
                kp = signingProps.getProperty("keyPassword")
                sf = signingProps.getProperty("storeFile")
                sp = signingProps.getProperty("storePassword")
            }

            if (ka == null){
                throw new GradleException("Property keyAlias not found in file: ${helloWorldAppSigningProperties}")
            } else if (kp == null) {
                throw new GradleException("Property keyPassword not found in file: ${helloWorldAppSigningProperties}")
            } else if (sf == null) {
                throw new GradleException("Property storeFile not found in file: ${helloWorldAppSigningProperties}")
            } else if (sp == null) {
                throw new GradleException("Property storePassword not found in file: ${helloWorldAppSigningProperties}")
            }

        } else {
            throw new GradleException("Properties file: ${helloWorldAppSigningProperties} not found!")
        }   

        //Add a signing configuration named "helloWorldApp_release" to the android build
        //Signing configuration properties that were loaded from an external properties file are here assigned
        println ""
        println "Adding new signingConfig helloWorldApp_release"
        android.signingConfigs{
            helloWorldApp_release{
                keyAlias ka
                keyPassword kp
                storeFile file(sf)
                storePassword sp                
            }
        }

        //Display the list of the available signigConfigs
        println ""
        println "Available signingConfigs:"
        android.signingConfigs.all { sc ->
            println "------------------"
            println sc.name
        }
        println "------------------"    

        //Display the list of the available buildTypes
        println ""
        println "Available buildTypes:"
        android.buildTypes.all { bt ->
            println "------------------"
            println bt.name
        }
        println "------------------"

        println ""
        println "SigningConfig assigned to the release buildType BEFORE overriding: ${android.buildTypes.release.signingConfig.name}"

        //Set the helloWorldApp_release signingConfig to the release buildType
        android.buildTypes.release.signingConfig android.signingConfigs.helloWorldApp_release
        println ""
        println "SigningConfig assigned to the release buildType AFTER overriding: ${android.buildTypes.release.signingConfig.name}"
        println ""

    }

}

I externalized the desired signingConfig properties to a file, whose location I referenced in the gradle.properties file:

gradle.properties

org.gradle.jvmargs=-Xmx1536M

....
....
....

//Signing config properties files
helloWorldAppSigningProperties=C:\\Users\\it056548\\.signing\\HelloWorldApp.properties

It resulted in a successful android build that addressed my needs when executing the command gradle -I init.gradle clean assembleRelease:

Project name: native

NDK is missing a "platforms" directory.
If you are using NDK, verify the ndk.dir is set to a valid NDK directory.  It is currently set to C:\android-sdks\ndk-bundle.
If you are not using NDK, unset the NDK variable from ANDROID_NDK_HOME or local.properties to remove this warning.


Found properties file: C:\Users\it056548\.signing\HelloWorldApp.properties!

Adding new signingConfig helloWorldApp_release

Available signingConfigs:
------------------
debug
------------------
helloWorldApp_release
------------------
releaseConfig
------------------

Available buildTypes:
------------------
debug
------------------
release
------------------

SigningConfig assigned to the release buildType BEFORE overriding: releaseConfig

SigningConfig assigned to the release buildType AFTER overriding: helloWorldApp_release

:clean
:preBuild UP-TO-DATE
:preReleaseBuild UP-TO-DATE
:checkReleaseManifest
:prepareReleaseDependencies
:compileReleaseAidl
:compileReleaseRenderscript
:generateReleaseBuildConfig
:generateReleaseResValues
:generateReleaseResources
:mergeReleaseResources
:processReleaseManifest
:processReleaseResources
:generateReleaseSources
:incrementalReleaseJavaCompilationSafeguard
:javaPreCompileRelease
:compileReleaseJavaWithJavac
:compileReleaseJavaWithJavac - is not incremental (e.g. outputs have changed, no previous execution, etc.).
:compileReleaseNdk NO-SOURCE
:compileReleaseSources
:lintVitalRelease
:mergeReleaseShaders
:compileReleaseShaders
:generateReleaseAssets
:mergeReleaseAssets
:transformClassesWithDexForRelease
:mergeReleaseJniLibFolders
:transformNativeLibsWithMergeJniLibsForRelease
:processReleaseJavaRes NO-SOURCE
:transformResourcesWithMergeJavaResForRelease
:validateSigningRelease
:packageRelease
:assembleRelease

BUILD SUCCESSFUL

Total time: 8.692 secs

Hope this can help!

like image 100
Quake Avatar answered Sep 10 '25 08:09

Quake