2

I want to automate inclusion of the latest generated third party licenses in Gradle.

Config:

  • Gradle 2.x
  • license-gradle-plugin 0.11.0

Code:

task beforeAssemble(dependsOn: assemble) << {
    downloadLicenses.execute()
    CopyToAssetsTask.execute()
}

task CopyToAssetsTask(type: Copy) {
   description = 'Copies generated Third Party Licenses into assets'
   from('$buildDir/reports/license') {
      include('dependency-license.html')
   }
   into '$buildDir/intermediates/assets/debug/legal'
}

apply plugin: 'license'

downloadLicenses {
    includeProjectDependencies = true
    reportByDependency = true
    reportByLicenseType = true
    dependencyConfiguration = "compile"
}

In command line: gradlew clean assembleDebug

The resulting APK does not include the generated file as I was hoping. I'm quite new to Gradle so maybe there is a simple explanation?

Alix
  • 2,630
  • 30
  • 72

4 Answers4

2

First some observations. The solution is at the end:

  • You are still thinking procedurally: Telling Gradle what to do when (i.e. what you do in task beforeAssemble). Make use of the task graph: Specify what the dependencies of a task are (see below for some of the possibilities). When you need the output of a task, just ask Gradle to execute that task, and Gradle will figure out the transitive tasks that that task depends on. It will execute all of those tasks: only once, and in the correct order.
  • This declaration: task beforeAssemble(dependsOn: assemble), does not make sense. You want the task to run before assemble, but by depending on assemble you achieved the reverse: assemble will be run before beforeAssemble.

How to specify dependencies? There are multiple options:

  • Using a direct dependency: dependsOn.
  • Referring to other tasks in the inputs of a task.
  • Setting the options of a task, which will automatically create a dependency. For example: If the from attribute of the Copy task is set to the outputs of another task, the Copy task will automatically add that other task as an input.

Here is the solution. You want two achieve two things:

  • Generate the license information during the build (at some particular point).
  • Include the license information in the archive(s).

Add this to your build script:

android {
    // ...

    // Add the output folder of the license plug-in as
    // a source folder for resources.
    sourceSets {
        main {
            resources {
                srcDir 'build/reports/license'
            }
        }
    }
}

downloadLicenses {
    includeProjectDependencies = true
    reportByDependency = true
    reportByLicenseType = true
    dependencyConfiguration = "compile"
}

// Add a dependency after the project has been evaluated, because
// the Android plug-in does not add tasks "generate*Resources" to
// the project immediately.
project.afterEvaluate {
    // Download the licenses when (actually: just before) the
    // resources are generated (for both the "debug" and the
    // "release" build types).

    // If you add/change build types, you have to add to/change
    // these task names.
    generateDebugResources.dependsOn tasks['downloadLicenses']
    generateReleaseResources.dependsOn tasks['downloadLicenses']
}
Johan Stuyts
  • 3,607
  • 1
  • 18
  • 21
  • This is very helpful, and it's almost working now but the files are not put into the assets folder, rather they are compiled in the root directory of the apk file. Also: `sourceSets.main.resources.srcDir` should be `sourceSets.main.resources.srcDirs` – Alix Aug 05 '15 at 07:34
  • A small tweak solved it. However, I would like to put it into a folder "legal" within assets (the generated file is now placed in the root assets folder). My tweak: `assets.srcDirs = ['src/main/assets', 'build/reports/license']` `mergeDebugAssets.dependsOn project.tasks.getByName('downloadLicenses')` `mergeReleaseAssets.dependsOn project.tasks.getByName('downloadLicenses')` – Alix Aug 05 '15 at 08:02
  • I have a similar issue, and Im struggling to get this working, could you paste a complete example @Alix of how you solved it? – tskulbru Aug 12 '15 at 10:38
  • Sure thing. I was holding back to let @JohanStuyts take the credit but I have now posted an answer – Alix Aug 12 '15 at 10:58
1

In my project (gradle 3.4.1), it works like this in the Android "Module:app" gradle file:

plugins {
   id "com.github.hierynomus.license" version "0.14.0"
}

license {
   include "**/*.java"
   strictCheck = false
   ignoreFailures = true
   skipExistingHeaders = true
}

downloadLicenses {
   includeProjectDependencies = true
   reportByDependency = true
   reportByLicenseType = false
   dependencyConfiguration = "compile"
   licenses = [
        (group('com.android.support')) : license('Apache License, Version 2.0', 'http://www.apache.org/licenses/LICENSE-2.0'),
        (group('com.android.support.constraint')) : license('Apache License, Version 2.0', 'http://www.apache.org/licenses/LICENSE-2.0'),
        (group('com.google.firebase')) : license('Apache License, Version 2.0', 'http://www.apache.org/licenses/LICENSE-2.0'),
        (group('com.google.android')) : license('Apache License, Version 2.0', 'http://www.apache.org/licenses/LICENSE-2.0'),
        (group('com.google.android.gms')) : license('Apache License, Version 2.0', 'http://www.apache.org/licenses/LICENSE-2.0')
]
}

apply plugin: 'com.android.application'

android {
   compileSdkVersion 25
   buildToolsVersion "25.0.2"

   defaultConfig {
    ...
   }

   sourceSets {
        main {
            assets.srcDirs = ['src/main/assets', 'build/licenses/']
        }
   }

   buildTypes {
    ...
   }
}

dependencies {
   compile 'com.android.support:appcompat-v7:25.3.1'
   compile 'com.android.support:multidex:1.0.1'
   compile 'com.android.support:support-v4:25.3.1'
   compile 'com.android.support:design:25.3.1'
   ...
}

task copyLicenseReport(type: Copy) {
   from('build/reports/license') {
    include '**/*.html'
    include '**/*.xml'
   }
   into 'build/licenses/thirdPartyLicenses'
}

project.afterEvaluate {
   copyLicenseReport.dependsOn project.tasks.getByName('downloadLicenses')
   preBuild.dependsOn copyLicenseReport
}

apply plugin: 'com.google.gms.google-services'
user2131878
  • 161
  • 1
  • 7
0

Try on changing CopyToAssetsTask into:

task CopyToAssetsTask << {
    copy {
        description = 'Copies generated Third Party Licenses into assets'
        from('$buildDir/reports/license') {
            include('dependency-license.html')
        }
        into '$buildDir/intermediates/assets/debug/legal'
    }
}

because right now, your copying is done in configuration phase.

mate00
  • 2,727
  • 5
  • 26
  • 34
  • 1
    With the change you propose copying will still occur during the execution phase. And that is where it should happen. Do not try to use the configuration phase for build steps. – Johan Stuyts Aug 03 '15 at 12:03
  • Ah, my mistake. I wanted to write "your copying is done in configuration phase". – mate00 Aug 03 '15 at 12:07
  • It is not. The instance of the `Copy` task is only configured during the configuration phase using `from`, `into`, etc. The actual copying will occur during the execution phase. – Johan Stuyts Aug 03 '15 at 12:14
  • I can confirm that changing had no effect – Alix Aug 03 '15 at 12:27
0

This solution worked for me and is a slightly modified version of the answer that Johan Stuyts posted.

One limitation though: The generated report will end up in the root assets folder instead of the intended subfolder "legal".

   buildscript {
       // ...
       dependencies {
          // ...
          classpath 'nl.javadude.gradle.plugins:license-gradle-plugin:0.11.0'
      }
   }

   android {
   // ...

   // Add the output folder of the license plug-in as
   // a source folder for assets.
      sourceSets {
          main {
              // ...
              assets.srcDirs = ['src/main/assets', 'build/reports/license']
          }
      }
   }

   downloadLicenses {
      includeProjectDependencies = true

      reportByDependency = true
      reportByLicenseType = false

      report.html.enabled = true
      report.xml.enabled = false

      dependencyConfiguration = "compile"
   }

   // Add a dependency after the project has been evaluated, because
   // the Android plug-in does not add tasks "merge*Assets" to
   // the project immediately.
   project.afterEvaluate {
      // Download the licenses when (actually: just before) the
      // assets are merged (for both the "debug" and the
      // "release" build types).

      // If you add/change build types, you have to add to/change
      // these task names.
      mergeDebugAssets.dependsOn project.tasks.getByName('downloadLicenses')
      mergeReleaseAssets.dependsOn project.tasks.getByName('downloadLicenses')
   }
Alix
  • 2,630
  • 30
  • 72