com.android.build.gradle.tasks.ProcessAndroidResources Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of gradle-core Show documentation
Show all versions of gradle-core Show documentation
Core library to build Android Gradle plugin.
The newest version!
/*
* Copyright (C) 2012 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.tasks;
import com.android.annotations.NonNull;
import com.android.annotations.Nullable;
import com.android.build.OutputFile;
import com.android.build.gradle.AndroidGradleOptions;
import com.android.build.gradle.internal.LoggingUtil;
import com.android.build.gradle.internal.aapt.AaptGradleFactory;
import com.android.build.gradle.internal.core.GradleVariantConfiguration;
import com.android.build.gradle.internal.dsl.AaptOptions;
import com.android.build.gradle.internal.incremental.InstantRunBuildContext;
import com.android.build.gradle.internal.scope.ConventionMappingHelper;
import com.android.build.gradle.internal.scope.TaskConfigAction;
import com.android.build.gradle.internal.scope.VariantOutputScope;
import com.android.build.gradle.internal.scope.VariantScope;
import com.android.build.gradle.internal.tasks.IncrementalTask;
import com.android.build.gradle.internal.variant.BaseVariantData;
import com.android.build.gradle.internal.variant.BaseVariantOutputData;
import com.android.build.gradle.internal.variant.SplitHandlingPolicy;
import com.android.builder.core.AndroidBuilder;
import com.android.builder.core.DefaultManifestParser;
import com.android.builder.core.VariantType;
import com.android.builder.dependency.level2.AndroidDependency;
import com.android.builder.dependency.level2.AtomDependency;
import com.android.builder.dependency.level2.Dependency;
import com.android.builder.dependency.level2.DependencyNode;
import com.android.builder.internal.aapt.Aapt;
import com.android.builder.internal.aapt.AaptPackageConfig;
import com.android.builder.model.MavenCoordinates;
import com.android.ide.common.blame.MergingLog;
import com.android.ide.common.blame.MergingLogRewriter;
import com.android.ide.common.blame.ParsingProcessOutputHandler;
import com.android.ide.common.blame.parser.ToolOutputParser;
import com.android.ide.common.blame.parser.aapt.AaptOutputParser;
import com.android.ide.common.process.ProcessException;
import com.android.ide.common.process.ProcessOutputHandler;
import com.android.utils.FileUtils;
import com.android.utils.StringHelper;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputDirectory;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.Nested;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.ParallelizableTask;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.incremental.IncrementalTaskInputs;
@ParallelizableTask
public class ProcessAndroidResources extends IncrementalTask {
private static final Logger LOG = Logging.getLogger(ProcessAndroidResources.class);
private File manifestFile;
private File instantRunManifestFile;
private File resDir;
private File sourceOutputDir;
private File textSymbolOutputDir;
private File packageOutputFile;
private File proguardOutputFile;
private File mainDexListProguardOutputFile;
private Collection resourceConfigs;
private String preferredDensity;
private List androidDependencies;
private List androidProvided;
private String packageForR;
private Collection splits;
private boolean enforceUniquePackageName;
private VariantType type;
private boolean debuggable;
private boolean pseudoLocalesEnabled;
private AaptOptions aaptOptions;
private File mergeBlameLogFolder;
private InstantRunBuildContext instantRunBuildContext;
private File instantRunSupportDir;
private Supplier baseFeature;
private Collection previousFeatures;
private VariantScope variantScope;
@Override
protected void doFullTaskAction() throws IOException {
// we have to clean the source folder output in case the package name changed.
File srcOut = getSourceOutputDir();
if (srcOut != null) {
FileUtils.cleanOutputDir(srcOut);
}
@Nullable
File resOutBaseNameFile = getPackageOutputFile();
// If are in instant run mode and we have an instant run enabled manifest
File instantRunManifest = getInstantRunManifestFile();
File manifestFileToPackage = instantRunBuildContext.isInInstantRunMode() &&
instantRunManifest != null && instantRunManifest.exists()
? instantRunManifest
: getManifestFile();
AndroidBuilder builder = getBuilder();
MergingLog mergingLog = new MergingLog(getMergeBlameLogFolder());
ProcessOutputHandler processOutputHandler = new ParsingProcessOutputHandler(
new ToolOutputParser(new AaptOutputParser(), getILogger()),
new MergingLogRewriter(mergingLog, builder.getErrorReporter()));
String preferredDensity =
getResourceConfigs().isEmpty()
? getPreferredDensity()
: null; /* when resConfigs are set, we should respect it */
try {
Aapt aapt = AaptGradleFactory.make(
getBuilder(),
processOutputHandler,
true,
variantScope.getGlobalScope().getProject(),
variantScope.getVariantConfiguration().getType(),
FileUtils.mkdirs(new File(getIncrementalFolder(), "aapt-temp")),
aaptOptions.getCruncherProcesses());
AaptPackageConfig.Builder config =
new AaptPackageConfig.Builder()
.setManifestFile(manifestFileToPackage)
.setOptions(getAaptOptions())
.setResourceDir(getResDir())
.setLibraries(getAndroidDependencies())
.setCustomPackageForR(getPackageForR())
.setSymbolOutputDir(getTextSymbolOutputDir())
.setSourceOutputDir(srcOut)
.setResourceOutputApk(resOutBaseNameFile)
.setProguardOutputFile(getProguardOutputFile())
.setMainDexListProguardOutputFile(getMainDexListProguardOutputFile())
.setVariantType(getType())
.setDebuggable(getDebuggable())
.setPseudoLocalize(getPseudoLocalesEnabled())
.setResourceConfigs(getResourceConfigs())
.setSplits(getSplits())
.setPreferredDensity(preferredDensity)
.setBaseFeature(getBaseFeature())
.setPreviousFeatures(getPreviousFeatures());
builder.processResources(aapt, config, getEnforceUniquePackageName());
if (resOutBaseNameFile != null && LOG.isInfoEnabled()) {
LOG.info("Aapt output file {}", resOutBaseNameFile.getAbsolutePath());
}
} catch (IOException | InterruptedException | ProcessException e) {
throw new RuntimeException(e);
}
}
public static class ConfigAction implements TaskConfigAction {
protected final VariantOutputScope scope;
protected final File symbolLocation;
private final boolean generateResourcePackage;
private final boolean generateLegacyMultidexMainDexProguardRules;
public ConfigAction(
@NonNull VariantOutputScope scope,
@NonNull File symbolLocation,
boolean generateResourcePackage,
boolean generateLegacyMultidexMainDexProguardRules) {
this.scope = scope;
this.symbolLocation = symbolLocation;
this.generateResourcePackage = generateResourcePackage;
this.generateLegacyMultidexMainDexProguardRules = generateLegacyMultidexMainDexProguardRules;
}
@NonNull
@Override
public String getName() {
return scope.getTaskName("process", "Resources");
}
@NonNull
@Override
public Class getType() {
return ProcessAndroidResources.class;
}
@Override
public void execute(@NonNull ProcessAndroidResources processResources) {
final BaseVariantOutputData variantOutputData = scope.getVariantOutputData();
final BaseVariantData extends BaseVariantOutputData> variantData =
scope.getVariantScope().getVariantData();
variantOutputData.processResourcesTask = processResources;
final GradleVariantConfiguration config = variantData.getVariantConfiguration();
processResources.setAndroidBuilder(scope.getGlobalScope().getAndroidBuilder());
processResources.setVariantName(config.getFullName());
processResources.variantScope = scope.getVariantScope();
processResources.setIncrementalFolder(
scope.getVariantScope().getIncrementalDir(getName()));
if (variantData.getSplitHandlingPolicy() ==
SplitHandlingPolicy.RELEASE_21_AND_AFTER_POLICY) {
Set allFilters = new HashSet<>();
allFilters.addAll(
variantData.getFilters(OutputFile.FilterType.DENSITY));
allFilters.addAll(
variantData.getFilters(OutputFile.FilterType.LANGUAGE));
processResources.splits = allFilters;
}
// only generate code if the density filter is null, and if we haven't generated
// it yet (if you have abi + density splits, then several abi output will have no
// densityFilter)
if (variantOutputData.getMainOutputFile()
.getFilter(OutputFile.DENSITY) == null
&& variantData.generateRClassTask == null) {
variantData.generateRClassTask = processResources;
processResources.enforceUniquePackageName = scope.getGlobalScope().getExtension()
.getEnforceUniquePackageName();
ConventionMappingHelper.map(
processResources,
"androidDependencies",
config::getFlatPackageAndroidLibraries);
ConventionMappingHelper.map(processResources, "packageForR",
new Callable() {
@Override
public String call() throws Exception {
String splitName = config.getSplitFromManifest();
if (splitName == null)
return config.getOriginalApplicationId();
else
return config.getOriginalApplicationId() + "." + splitName;
}
});
// TODO: unify with generateBuilderConfig, compileAidl, and library packaging somehow?
processResources
.setSourceOutputDir(scope.getVariantScope().getRClassSourceOutputDir());
processResources.setTextSymbolOutputDir(symbolLocation);
if (config.getBuildType().isMinifyEnabled()) {
if (config.getBuildType().isShrinkResources() && config.getJackOptions().isEnabled()) {
LoggingUtil.displayWarning(Logging.getLogger(getClass()),
scope.getGlobalScope().getProject(),
"shrinkResources does not yet work with useJack=true");
}
processResources.setProguardOutputFile(
scope.getVariantScope().getProcessAndroidResourcesProguardOutputFile());
} else if (config.getBuildType().isShrinkResources()) {
LoggingUtil.displayWarning(Logging.getLogger(getClass()),
scope.getGlobalScope().getProject(),
"To shrink resources you must also enable ProGuard");
}
if (generateLegacyMultidexMainDexProguardRules) {
processResources.setAaptMainDexListProguardOutputFile(
scope.getVariantScope().getManifestKeepListProguardFile());
}
}
ConventionMappingHelper.map(processResources, "manifestFile", new Callable() {
@Override
public File call() throws Exception {
return variantOutputData.manifestProcessorTask.getOutputFile();
}
});
ConventionMappingHelper.map(processResources, "instantRunManifestFile",
new Callable() {
@Override
public File call() throws Exception {
return variantOutputData.manifestProcessorTask.getInstantRunManifestOutputFile();
}
});
ConventionMappingHelper.map(processResources, "resDir", new Callable() {
@Override
public File call() throws Exception {
return scope.getVariantScope().getFinalResourcesDir();
}
});
if (generateResourcePackage) {
processResources.setPackageOutputFile(scope.getProcessResourcePackageOutputFile());
}
processResources.setType(config.getType());
processResources.setDebuggable(config.getBuildType().isDebuggable());
processResources.setAaptOptions(scope.getGlobalScope().getExtension().getAaptOptions());
processResources
.setPseudoLocalesEnabled(config.getBuildType().isPseudoLocalesEnabled());
ConventionMappingHelper.map(processResources, "resourceConfigs",
new Callable>() {
@Override
public Collection call() throws Exception {
Collection resConfigs =
config.getMergedFlavor().getResourceConfigurations();
if (resConfigs.size() == 1 &&
Iterators.getOnlyElement(resConfigs.iterator())
.equals("auto")) {
return variantData.discoverListOfResourceConfigsNotDensities();
}
return config.getMergedFlavor().getResourceConfigurations();
}
});
ConventionMappingHelper.map(processResources, "preferredDensity",
new Callable() {
@Override
@Nullable
public String call() throws Exception {
String variantFilter = variantOutputData.getMainOutputFile()
.getFilter(OutputFile.DENSITY);
if (variantFilter != null) {
return variantFilter;
}
return AndroidGradleOptions.getBuildTargetDensity(
scope.getGlobalScope().getProject());
}
});
processResources.setMergeBlameLogFolder(
scope.getVariantScope().getResourceBlameLogDir());
processResources.instantRunBuildContext =
scope.getVariantScope().getInstantRunBuildContext();
processResources.setPreviousFeatures(ImmutableSet.of());
processResources.setBaseFeature(() -> {
AtomDependency baseAtom = scope
.getVariantScope()
.getVariantConfiguration()
.getPackageDependencies()
.getBaseAtom();
return baseAtom != null ? baseAtom.getResourcePackage() : null;
});
}
}
public static class AtomConfigAction extends ConfigAction {
@NonNull
private final DependencyNode atomNode;
@NonNull
private final AtomDependency atomDependency;
@NonNull
private final Map