-->

Copy generated third party licenses to assets

2019-07-09 02:24发布

问题:

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?

回答1:

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']
}


回答2:

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'


回答3:

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.



回答4:

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')
   }