blob: 894352f10678bbb9a36841ef987358d90090b76f [file] [log] [blame]
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.build.gradle.internal.tasks.multidex
import com.android.build.gradle.internal.PostCompilationData
import com.android.build.gradle.internal.scope.ConventionMappingHelper
import com.android.build.gradle.internal.scope.TaskConfigAction
import com.android.build.gradle.internal.scope.VariantScope
import com.android.build.gradle.internal.tasks.DefaultAndroidTask
import com.android.build.gradle.internal.variant.BaseVariantOutputData
import com.google.common.base.Charsets
import com.google.common.io.Files
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.OutputFile
import org.gradle.api.tasks.TaskAction
import org.xml.sax.Attributes
import org.xml.sax.helpers.DefaultHandler
import javax.xml.parsers.SAXParser
import javax.xml.parsers.SAXParserFactory
class CreateManifestKeepList extends DefaultAndroidTask {
@InputFile
File manifest
@OutputFile
File outputFile
@InputFile @Optional
File proguardFile
Closure filter
@TaskAction
void generateKeepListFromManifest() {
SAXParser parser = SAXParserFactory.newInstance().newSAXParser()
Writer out = new BufferedWriter(new FileWriter(getOutputFile()))
try {
parser.parse(getManifest(), new ManifestHandler(out))
// add a couple of rules that cannot be easily parsed from the manifest.
out.write(
"""-keep public class * extends android.app.backup.BackupAgent {
<init>();
}
-keep public class * extends java.lang.annotation.Annotation {
*;
}
""")
if (proguardFile != null) {
out.write(Files.toString(proguardFile, Charsets.UTF_8))
}
} finally {
out.close()
}
}
private static String DEFAULT_KEEP_SPEC = "{ <init>(); }"
private static Map<String, String> KEEP_SPECS = [
'application' : """{
<init>();
void attachBaseContext(android.content.Context);
}""",
'activity' : DEFAULT_KEEP_SPEC,
'service' : DEFAULT_KEEP_SPEC,
'receiver' : DEFAULT_KEEP_SPEC,
'provider' : DEFAULT_KEEP_SPEC,
'instrumentation' : DEFAULT_KEEP_SPEC,
]
private class ManifestHandler extends DefaultHandler {
private Writer out
ManifestHandler(Writer out) {
this.out = out
}
@Override
void startElement(String uri, String localName, String qName, Attributes attr) {
String keepSpec = (String)CreateManifestKeepList.KEEP_SPECS[qName]
if (keepSpec) {
boolean keepIt = true
if (CreateManifestKeepList.this.filter) {
// for ease of use, turn 'attr' into a simple map
Map<String, String> attrMap = [:]
for (int i = 0; i < attr.getLength(); i++) {
attrMap[attr.getQName(i)] = attr.getValue(i)
}
keepIt = CreateManifestKeepList.this.filter(qName, attrMap)
}
if (keepIt) {
out.write((String)"-keep class ${attr.getValue('android:name')} $keepSpec\n")
}
}
}
}
public static class ConfigAction implements TaskConfigAction<CreateManifestKeepList> {
VariantScope scope;
PostCompilationData pcData;
ConfigAction(VariantScope scope, PostCompilationData pcData) {
this.scope = scope
this.pcData = pcData
}
@Override
String getName() {
return scope.getTaskName("collect", "MultiDexComponents");
}
@Override
Class<CreateManifestKeepList> getType() {
return CreateManifestKeepList
}
@Override
void execute(CreateManifestKeepList manifestKeepListTask) {
manifestKeepListTask.setVariantName(scope.getVariantConfiguration().getFullName())
// since all the output have the same manifest, besides the versionCode,
// we can take any of the output and use that.
final BaseVariantOutputData output = scope.variantData.outputs.get(0)
ConventionMappingHelper.map(manifestKeepListTask, "manifest") {
output.getScope().getManifestOutputFile()
}
manifestKeepListTask.proguardFile = scope.variantConfiguration.getMultiDexKeepProguard()
manifestKeepListTask.outputFile = scope.getManifestKeepListFile();
//variant.ext.collectMultiDexComponents = manifestKeepListTask
}
}
}