Question

I need to post-process my APK by adding a second signature, so I'm trying to understand how to hook into the build process at that point. my first attempt,

task doubleSign {
  if (signing.androidBuildExists) {
    android.buildTypes.all { type ->
      tasks.("assemble${type.name.capitalize()}").finalizedBy doDoubleSign
    }
  }
}

okay fine. but if any of the install* tasks are executed, then much to my surprise, assemble* isn't in the dependency tree. so next i tried adding the line,

tasks.("install${type.name.capitalize()}").dependsOn doDoubleSign

however, gradle tells me that task doesn't exist!

> Could not find property 'installDebug' on task set.
Was it helpful?

Solution

installDebug won't be present when that code is executed because the android plugin creates its tasks in the afterEvaluate phase.

What you should do:

android {
  applicationVariants.all { variant ->
    if (!variant.isSigningReady()) {
      // only add double signing on variants that are signed with
      // default signing method.
      return
    }

    // get output file
    def outputFile = variant.outputFile

    // add new signing task.
    def signingTask = project.tasks.create("double${variant.name}Sign", MyCustomSigning)
    // configure task
    signingTask.inputFile = outputFile
    // create the final apk name using baseName to guarantee it's unique.
    signingTask.outputFile = new File(project.buildDir, "apks/${project.name}-${variant.baseName}-2sign.apk")

    // configure the task to be run after the default signing task.
    signingTask.dependsOn variant.packageApplication

    // configure zip align task to use the output of the 2nd signing task,
    // and also to run after 2nd signing task.
    variant.zipAlign.inputFile = signingTask.outputFile
    variant.zipAlign.dependsOn signingTask
  }
}

Note that if you don't run zipalign (but really you should) you'll have to tweak the end to make variant.assemble depend on your signing task instead and to set the output of your signing task to variant.outputFile so that deployment from command line or IDE still works.

For the actual signing you would do a custom task with the annotations so that it only runs if the input file actually change.

class MyCustomSigning extends DefaultTask {
  @InputFile
  File inputFile

  @OutputFile
  File outputFile

  @TaskAction
  void sign() {
    // call script to sign inputFile into outputFile
    ...
  }
}

OTHER TIPS

Even though this question has been answered, I want to share the solution that worked best for me.

All I needed was a suitable hook to post-process a completely finished apk. For this I used the hook "assemble.doLast":

android {
    /* ... */

    applicationVariants.all { variant ->
        variant.assemble.doLast {
            variant.outputs.each { output ->
                File apk = output.outputFile
                // Post process apk
            }
        }
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top