Add generated file to META-INF

I’m using gradle 2.3 to build android APKs and AARs (With ‘android’ and ‘android-library’ plugins, respectively).

I’m trying to generate a file during the build that will be picked up into the META-INF directory in the resulting APK.
I can successfully generate the file, but it doesn’t get packaged.

task createVersionInformation  {
  def resDir = new File(buildDir, 'generated/resources/META-INF/')
  def destDir = new File(resDir, 'META-INF/')
  doLast {
    destDir.mkdirs()
    def vfile = new File(destDir, 'BUILD_INFO')
    vfile.text = "build info goes here"
  }
}

tasks.preBuild.dependsOn createVersionInformation

The file shows up in the ./build/generated/ dir, but not in the apk.

Any ideas on how to get it to work?

Did you ever find a solution to your problem? I have a similar situation.

I found a solution, yeah:

My final commit for this topic looks like this:

-  tasks.findAll { task -> task.name.startsWith('package') }.each { t ->
-    t.dependsOn createVersionInformation
-  }
+  tasks.findAll { task ->
+    task.name.startsWith('merge') && task.name.endsWith('Resources')
+  }.each { t -> t.dependsOn createVersionInformation }

Basically make sure the file is generated before merge*Resources tasks. I think. This ends up working in all my projects, as far as I can tell.

Thank you, Aviv! What is the directory you write your “BUILD_INFO” file into in order for it to be included in META-INF in the APK? I tried the directory you included in your original post above but it didn’t seem to work.

Best regards,

John

The directory I use seems ad-hoc, but I’m adding it to the main.resources, which may be the actual trick.

task createVersionInformation  {
  def resDir = new File(buildDir, 'generated/buildinfo/')
  def destDir = new File(resDir, 'META-INF/')

  android {
    sourceSets {
      main.resources {
        srcDir resDir
      }
    }
  }

  doLast {
    destDir.mkdirs()
    def vfile = new File(destDir, 'BUILD_INFO')

    def stdout = new ByteArrayOutputStream()
    exec {
      commandLine 'git', 'log', '-1', '--format=%H'
      standardOutput = stdout
    }
    def git_hash = stdout.toString().trim()

    stdout.reset()
    exec {
      commandLine 'git', 'config', 'remote.origin.url'
      standardOutput = stdout
    }
    def remote = stdout.toString().trim()

    def dirty = exec {
      commandLine 'git', 'diff-index', '--quiet', 'HEAD'
      ignoreExitValue true
    }
    dirty = dirty.getExitValue() == 0 ?
      ' (Clean workspace)' : '-DIRTY using dirty workspace!'

    def repo_info = "$remote at $git_hash$dirty"

    vfile.text = "$repo_info\n"
  }
}

project.afterEvaluate {
  tasks.findAll { task ->
    task.name.startsWith('merge') && task.name.endsWith('Resources')
  }.each { t -> t.dependsOn createVersionInformation }
}

(This is the full file that handles my buildinfo, except for a lot of local magic to generate some more of the version info)

Thank you, Aviv! I can get your code to work, but in my case I am copying files into META-INF instead of creating the file from scratch. I must have something off with the copy; the files make it into generated folder, but not into the APK.

Thank you again for this example!

John

I got this to work and wanted to share the final code; this is an example of how to copy a LICENSE file into the APK’s META-INF directory; many thanks to Aviv for his solution (which this is very close to):

    task put_files_in_META_INF  {
    	def resDir = new File(buildDir, 'generated/files_for_META_INF/')
    	def destDir = new File(resDir, 'META-INF/')
    	// THIS IS KEY: Add resDir as a resource directory so that it is
    	//              automatically included in the APK
    	android {
    		sourceSets {
    			main.resources {
    				srcDir resDir
    			}
    		}
    	}
    	doLast {
    		destDir.mkdirs()
    		copy {
    			into destDir
    			from <SOURCE_LOCATION_OF_LICENSE_FILE>
    		}
    	}
    }
    // Specify when put_files_in_META_INF should run
    project.afterEvaluate {
    	tasks.findAll { task ->
    		task.name.startsWith('merge') && task.name.endsWith('Resources')
	  }.each { t -> t.dependsOn put_files_in_META_INF }
	}