blob: 4467c823c746073ac515a3b94237ce88e80b316f [file] [log] [blame]
// Copyright 2015 The Bazel Authors. All rights reserved.
//
// 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.google.devtools.build.lib.rules.android;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.devtools.build.lib.syntax.Type.STRING;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.FileProvider;
import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
import com.google.devtools.build.lib.analysis.RuleContext;
import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.analysis.config.CompilationMode;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidManifestMerger;
import com.google.devtools.build.lib.rules.android.ResourceContainer.Builder.JavaPackageSource;
import com.google.devtools.build.lib.rules.android.ResourceContainer.ResourceType;
import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.util.Preconditions;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.annotation.Nullable;
/** Represents a AndroidManifest, that may have been merged from dependencies. */
public final class ApplicationManifest {
public static ApplicationManifest fromResourcesRule(RuleContext ruleContext) {
final AndroidResourcesProvider resources = AndroidCommon.getAndroidResources(ruleContext);
if (resources == null) {
ruleContext.attributeError("manifest", "a resources or manifest attribute is mandatory.");
return null;
}
return new ApplicationManifest(
ruleContext, Iterables.getOnlyElement(resources.getDirectAndroidResources()).getManifest());
}
public ApplicationManifest createSplitManifest(
RuleContext ruleContext, String splitName, boolean hasCode) {
// aapt insists that manifests be called AndroidManifest.xml, even though they have to be
// explicitly designated as manifests on the command line
Artifact result = AndroidBinary.getDxArtifact(
ruleContext, "split_" + splitName + "/AndroidManifest.xml");
SpawnAction.Builder builder = new SpawnAction.Builder()
.setExecutable(ruleContext.getExecutablePrerequisite("$build_split_manifest", Mode.HOST))
.setProgressMessage("Creating manifest for split " + splitName)
.setMnemonic("AndroidBuildSplitManifest")
.addArgument("--main_manifest")
.addInputArgument(manifest)
.addArgument("--split_manifest")
.addOutputArgument(result)
.addArgument("--split")
.addArgument(splitName)
.addArgument(hasCode ? "--hascode" : "--nohascode");
String overridePackage = manifestValues.get("applicationId");
if (overridePackage != null) {
builder
.addArgument("--override_package")
.addArgument(overridePackage);
}
ruleContext.registerAction(builder.build(ruleContext));
return new ApplicationManifest(ruleContext, result);
}
public ApplicationManifest addMobileInstallStubApplication(RuleContext ruleContext)
throws InterruptedException {
Artifact stubManifest = ruleContext.getImplicitOutputArtifact(
AndroidRuleClasses.MOBILE_INSTALL_STUB_APPLICATION_MANIFEST);
SpawnAction.Builder builder = new SpawnAction.Builder()
.setExecutable(ruleContext.getExecutablePrerequisite("$stubify_manifest", Mode.HOST))
.setProgressMessage("Injecting mobile install stub application")
.setMnemonic("InjectMobileInstallStubApplication")
.addArgument("--mode=mobile_install")
.addArgument("--input_manifest")
.addInputArgument(manifest)
.addArgument("--output_manifest")
.addOutputArgument(stubManifest)
.addArgument("--output_datafile")
.addOutputArgument(ruleContext.getImplicitOutputArtifact(
AndroidRuleClasses.MOBILE_INSTALL_STUB_APPLICATION_DATA));
String overridePackage = manifestValues.get("applicationId");
if (overridePackage != null) {
builder.addArgument("--override_package");
builder.addArgument(overridePackage);
}
ruleContext.registerAction(builder.build(ruleContext));
return new ApplicationManifest(ruleContext, stubManifest);
}
public ApplicationManifest addInstantRunStubApplication(RuleContext ruleContext)
throws InterruptedException {
Artifact stubManifest = ruleContext.getImplicitOutputArtifact(
AndroidRuleClasses.INSTANT_RUN_STUB_APPLICATION_MANIFEST);
SpawnAction.Builder builder = new SpawnAction.Builder()
.setExecutable(ruleContext.getExecutablePrerequisite("$stubify_manifest", Mode.HOST))
.setProgressMessage("Injecting instant run stub application")
.setMnemonic("InjectInstantRunStubApplication")
.addArgument("--mode=instant_run")
.addArgument("--input_manifest")
.addInputArgument(manifest)
.addArgument("--output_manifest")
.addOutputArgument(stubManifest);
ruleContext.registerAction(builder.build(ruleContext));
return new ApplicationManifest(ruleContext, stubManifest);
}
public static ApplicationManifest fromRule(RuleContext ruleContext) {
return new ApplicationManifest(
ruleContext, ruleContext.getPrerequisiteArtifact("manifest", Mode.TARGET));
}
public static ApplicationManifest fromExplicitManifest(
RuleContext ruleContext, Artifact manifest) {
return new ApplicationManifest(ruleContext, manifest);
}
/**
* Generates an empty manifest for a rule that does not directly specify resources.
*
* <p><strong>Note:</strong> This generated manifest can then be used as the primary manifest
* when merging with dependencies.
*
* @return the generated ApplicationManifest
*/
public static ApplicationManifest generatedManifest(RuleContext ruleContext) {
Artifact generatedManifest = ruleContext.getUniqueDirectoryArtifact(
ruleContext.getRule().getName() + "_generated", new PathFragment("AndroidManifest.xml"),
ruleContext.getBinOrGenfilesDirectory());
String manifestPackage = AndroidCommon.getJavaPackage(ruleContext);
String contents = Joiner.on("\n").join(
"<?xml version=\"1.0\" encoding=\"utf-8\"?>",
"<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"",
" package=\"" + manifestPackage + "\">",
" <application>",
" </application>",
"</manifest>");
ruleContext
.getAnalysisEnvironment()
.registerAction(
FileWriteAction.create(
ruleContext, generatedManifest, contents, /*makeExecutable=*/ false));
return new ApplicationManifest(ruleContext, generatedManifest);
}
private static ImmutableMap<String, String> getManifestValues(RuleContext context) {
Map<String, String> manifestValues = new TreeMap<>();
// applicationId is set from manifest_values or android_resources.rename_manifest_package
// with descending priority.
AndroidResourcesProvider resourcesProvider = AndroidCommon.getAndroidResources(context);
if (resourcesProvider != null) {
ResourceContainer resourceContainer = Iterables.getOnlyElement(
resourcesProvider.getDirectAndroidResources());
if (resourceContainer.getRenameManifestPackage() != null) {
manifestValues.put("applicationId", resourceContainer.getRenameManifestPackage());
}
}
if (context.attributes().isAttributeValueExplicitlySpecified("manifest_values")) {
manifestValues.putAll(context.attributes().get("manifest_values", Type.STRING_DICT));
}
for (String variable : manifestValues.keySet()) {
manifestValues.put(
variable, context.expandMakeVariables("manifest_values", manifestValues.get(variable)));
}
return ImmutableMap.copyOf(manifestValues);
}
private final Artifact manifest;
private final ImmutableMap<String, String> manifestValues;
private ApplicationManifest(RuleContext ruleContext, Artifact manifest) {
this.manifest = manifest;
this.manifestValues = getManifestValues(ruleContext);
}
public ApplicationManifest mergeWith(RuleContext ruleContext, ResourceDependencies resourceDeps) {
Map<Artifact, Label> mergeeManifests = getMergeeManifests(resourceDeps.getResources());
boolean legacy = true;
if (ruleContext.isLegalFragment(AndroidConfiguration.class)
&& ruleContext.getRule().isAttrDefined("manifest_merger", STRING)) {
AndroidManifestMerger merger = AndroidManifestMerger.fromString(
ruleContext.attributes().get("manifest_merger", STRING));
if (merger == null) {
merger = ruleContext.getFragment(AndroidConfiguration.class).getManifestMerger();
}
legacy = merger == AndroidManifestMerger.LEGACY;
}
if (legacy) {
if (!mergeeManifests.isEmpty()) {
Artifact outputManifest = ruleContext.getUniqueDirectoryArtifact(
ruleContext.getRule().getName() + "_merged", "AndroidManifest.xml",
ruleContext.getBinOrGenfilesDirectory());
AndroidManifestMergeHelper.createMergeManifestAction(ruleContext, getManifest(),
mergeeManifests.keySet(), ImmutableList.of("all"), outputManifest);
return new ApplicationManifest(ruleContext, outputManifest);
}
} else {
if (!mergeeManifests.isEmpty() || !manifestValues.isEmpty()) {
Artifact outputManifest = ruleContext.getUniqueDirectoryArtifact(
ruleContext.getRule().getName() + "_merged", "AndroidManifest.xml",
ruleContext.getBinOrGenfilesDirectory());
Artifact mergeLog = ruleContext.getUniqueDirectoryArtifact(
ruleContext.getRule().getName() + "_merged", "manifest_merger_log.txt",
ruleContext.getBinOrGenfilesDirectory());
new ManifestMergerActionBuilder(ruleContext)
.setManifest(getManifest())
.setMergeeManifests(mergeeManifests)
.setLibrary(false)
.setManifestValues(manifestValues)
.setCustomPackage(AndroidCommon.getJavaPackage(ruleContext))
.setManifestOutput(outputManifest)
.setLogOut(mergeLog)
.build(ruleContext);
return new ApplicationManifest(ruleContext, outputManifest);
}
}
return this;
}
private static Map<Artifact, Label> getMergeeManifests(
Iterable<ResourceContainer> resourceContainers) {
ImmutableSortedMap.Builder<Artifact, Label> builder =
ImmutableSortedMap.orderedBy(Artifact.EXEC_PATH_COMPARATOR);
for (ResourceContainer r : resourceContainers) {
if (r.isManifestExported()) {
builder.put(r.getManifest(), r.getLabel());
}
}
return builder.build();
}
public ApplicationManifest renamePackage(RuleContext ruleContext, String customPackage) {
if (isNullOrEmpty(customPackage)) {
return this;
}
Artifact outputManifest = ruleContext.getUniqueDirectoryArtifact(
ruleContext.getRule().getName() + "_renamed", "AndroidManifest.xml",
ruleContext.getBinOrGenfilesDirectory());
new ManifestMergerActionBuilder(ruleContext)
.setManifest(getManifest())
.setLibrary(true)
.setCustomPackage(customPackage)
.setManifestOutput(outputManifest)
.build(ruleContext);
return new ApplicationManifest(ruleContext, outputManifest);
}
/** Packages up the manifest with assets from the rule and dependent resources.
* @throws InterruptedException */
public ResourceApk packWithAssets(
Artifact resourceApk,
RuleContext ruleContext,
ResourceDependencies resourceDeps,
Artifact rTxt,
boolean incremental,
Artifact proguardCfg) throws InterruptedException {
LocalResourceContainer data = new LocalResourceContainer.Builder(ruleContext)
.withAssets(
AndroidCommon.getAssetDir(ruleContext),
ruleContext.getPrerequisitesIf(
// TODO(bazel-team): Remove the ResourceType construct.
ResourceType.ASSETS.getAttribute(),
Mode.TARGET,
FileProvider.class)).build();
return createApk(
ruleContext,
false, /* isLibrary */
resourceDeps,
ResourceConfigurationFilter.empty(ruleContext),
ImmutableList.<String>of(), /* uncompressedExtensions */
true, /* crunchPng */
ImmutableList.<String>of(), /* densities */
incremental,
ResourceContainer.builderFromRule(ruleContext)
.setAssetsAndResourcesFrom(data)
.setManifest(getManifest())
.setRTxt(rTxt)
.setApk(resourceApk)
.build(),
data,
proguardCfg,
null, /* Artifact mainDexProguardCfg */
null, /* Artifact manifestOut */
null /* Artifact mergedResources */,
null /* Artifact dataBindingInfoZip */);
}
/** Packages up the manifest with resource and assets from the LocalResourceContainer. */
public ResourceApk packWithDataAndResources(
RuleContext ruleContext,
LocalResourceContainer data,
ResourceDependencies resourceDeps,
Artifact rTxt,
Artifact symbols,
Artifact manifestOut,
Artifact mergedResources,
boolean alwaysExportManifest) throws InterruptedException {
if (ruleContext.hasErrors()) {
return null;
}
ResourceContainer.Builder resourceContainer =
ResourceContainer.builderFromRule(ruleContext)
.setAssetsAndResourcesFrom(data)
.setManifest(getManifest())
.setRTxt(rTxt)
.setSymbols(symbols)
.setJavaPackageFrom(JavaPackageSource.MANIFEST);
if (alwaysExportManifest) {
resourceContainer.setManifestExported(true);
}
return createApk(
ruleContext,
true, /* isLibrary */
resourceDeps,
ResourceConfigurationFilter.empty(ruleContext),
ImmutableList.<String>of(), /* List<String> uncompressedExtensions */
false, /* crunchPng */
ImmutableList.<String>of(), /* List<String> densities */
false, /* incremental */
resourceContainer.build(),
data,
null, /* Artifact proguardCfg */
null, /* Artifact mainDexProguardCfg */
manifestOut,
mergedResources,
null /* Artifact dataBindingInfoZip */);
}
/** Packages up the manifest with resource and assets from the rule and dependent resources. */
public ResourceApk packWithDataAndResources(
@Nullable Artifact resourceApk,
RuleContext ruleContext,
boolean isLibrary,
ResourceDependencies resourceDeps,
Artifact rTxt,
Artifact symbols,
ResourceConfigurationFilter configurationFilters,
List<String> uncompressedExtensions,
boolean crunchPng,
List<String> densities,
boolean incremental,
Artifact proguardCfg,
@Nullable Artifact mainDexProguardCfg,
Artifact manifestOut,
Artifact mergedResources,
Artifact dataBindingInfoZip) throws InterruptedException {
LocalResourceContainer data = new LocalResourceContainer.Builder(ruleContext)
.withAssets(
AndroidCommon.getAssetDir(ruleContext),
ruleContext.getPrerequisitesIf(
// TODO(bazel-team): Remove the ResourceType construct.
ResourceType.ASSETS.getAttribute(),
Mode.TARGET,
FileProvider.class))
.withResources(
ruleContext.getPrerequisites(
"resource_files",
Mode.TARGET,
FileProvider.class)).build();
if (ruleContext.hasErrors()) {
return null;
}
return createApk(
ruleContext,
isLibrary,
resourceDeps,
configurationFilters,
uncompressedExtensions,
crunchPng,
densities,
incremental,
ResourceContainer.builderFromRule(ruleContext)
.setAssetsAndResourcesFrom(data)
.setManifest(getManifest())
.setRTxt(rTxt)
.setSymbols(symbols)
.setApk(resourceApk)
.build(),
data,
proguardCfg,
mainDexProguardCfg,
manifestOut,
mergedResources, dataBindingInfoZip);
}
private ResourceApk createApk(
RuleContext ruleContext,
boolean isLibrary,
ResourceDependencies resourceDeps,
ResourceConfigurationFilter configurationFilters,
List<String> uncompressedExtensions,
boolean crunchPng,
List<String> densities,
boolean incremental,
ResourceContainer maybeInlinedResourceContainer,
LocalResourceContainer data,
Artifact proguardCfg,
@Nullable Artifact mainDexProguardCfg,
Artifact manifestOut,
Artifact mergedResources,
Artifact dataBindingInfoZip) throws InterruptedException {
ResourceContainer resourceContainer = checkForInlinedResources(
maybeInlinedResourceContainer,
resourceDeps.getResources(), // TODO(bazel-team): Figure out if we really need to check
// the ENTIRE transitive closure, or just the direct dependencies. Given that each rule with
// resources would check for inline resources, we can rely on the previous rule to have
// checked its dependencies.
ruleContext);
if (ruleContext.hasErrors()) {
return null;
}
// Filter the resources during analysis to prevent processing of and dependencies on unwanted
// resources during execution.
resourceContainer = resourceContainer.filter(configurationFilters);
resourceDeps = resourceDeps.filter(configurationFilters);
ResourceContainer processed;
if (isLibrary && AndroidCommon.getAndroidConfig(ruleContext).useParallelResourceProcessing()) {
// android_library should only build the APK one way (!incremental).
Preconditions.checkArgument(!incremental);
Artifact rJavaClassJar = ruleContext.getImplicitOutputArtifact(
AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR);
if (resourceContainer.getSymbols() != null) {
new AndroidResourceParsingActionBuilder(ruleContext)
.withPrimary(resourceContainer)
.setParse(data)
.setOutput(resourceContainer.getSymbols())
.build(ruleContext);
}
AndroidResourceMergingActionBuilder resourcesMergerBuilder =
new AndroidResourceMergingActionBuilder(ruleContext)
.setJavaPackage(resourceContainer.getJavaPackage())
.withPrimary(resourceContainer)
.withDependencies(resourceDeps)
.setMergedResourcesOut(mergedResources)
.setManifestOut(manifestOut)
.setClassJarOut(rJavaClassJar)
.setDataBindingInfoZip(dataBindingInfoZip);
ResourceContainer merged = resourcesMergerBuilder.build(ruleContext);
AndroidResourceValidatorActionBuilder validatorBuilder =
new AndroidResourceValidatorActionBuilder(ruleContext)
.setJavaPackage(merged.getJavaPackage())
.setDebug(
ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT)
.setMergedResources(mergedResources)
.withPrimary(merged)
.setSourceJarOut(merged.getJavaSourceJar())
.setRTxtOut(merged.getRTxt());
processed = validatorBuilder.build(ruleContext);
} else {
AndroidResourcesProcessorBuilder builder =
new AndroidResourcesProcessorBuilder(ruleContext)
.setLibrary(isLibrary)
.setApkOut(resourceContainer.getApk())
.setConfigurationFilters(configurationFilters)
.setUncompressedExtensions(uncompressedExtensions)
.setCrunchPng(crunchPng)
.setJavaPackage(resourceContainer.getJavaPackage())
.setDebug(ruleContext.getConfiguration().getCompilationMode() != CompilationMode.OPT)
.setManifestOut(manifestOut)
.setMergedResourcesOut(mergedResources)
.withPrimary(resourceContainer)
.withDependencies(resourceDeps)
.setDensities(densities)
.setProguardOut(proguardCfg)
.setMainDexProguardOut(mainDexProguardCfg)
.setDataBindingInfoZip(dataBindingInfoZip)
.setApplicationId(manifestValues.get("applicationId"))
.setVersionCode(manifestValues.get("versionCode"))
.setVersionName(manifestValues.get("versionName"));
if (!incremental) {
builder
.setRTxtOut(resourceContainer.getRTxt())
.setSymbols(resourceContainer.getSymbols())
.setSourceJarOut(resourceContainer.getJavaSourceJar());
}
processed = builder.build(ruleContext);
}
return new ResourceApk(
resourceContainer.getApk(), processed.getJavaSourceJar(), processed.getJavaClassJar(),
resourceDeps, processed, processed.getManifest(),
proguardCfg, mainDexProguardCfg, false);
}
private static ResourceContainer checkForInlinedResources(ResourceContainer resourceContainer,
Iterable<ResourceContainer> resourceContainers, RuleContext ruleContext) {
// Dealing with Android library projects
if (Iterables.size(resourceContainers) > 1) {
if (resourceContainer.getConstantsInlined()
&& !resourceContainer.getArtifacts(ResourceType.RESOURCES).isEmpty()) {
ruleContext.ruleError("This android binary depends on an android "
+ "library project, so the resources '"
+ AndroidCommon.getAndroidResources(ruleContext).getLabel()
+ "' should have the attribute inline_constants set to 0");
return null;
}
}
return resourceContainer;
}
/** Uses the resource apk from the resources attribute, as opposed to recompiling. */
public ResourceApk useCurrentResources(
RuleContext ruleContext, Artifact proguardCfg, @Nullable Artifact mainDexProguardCfg) {
ResourceContainer resourceContainer = Iterables.getOnlyElement(
AndroidCommon.getAndroidResources(ruleContext).getDirectAndroidResources());
new AndroidAaptActionHelper(
ruleContext,
resourceContainer.getManifest(),
Lists.newArrayList(resourceContainer))
.createGenerateProguardAction(proguardCfg, mainDexProguardCfg);
return new ResourceApk(
resourceContainer.getApk(),
null /* javaSrcJar */,
null /* javaClassJar */,
ResourceDependencies.empty(),
resourceContainer,
manifest,
proguardCfg,
mainDexProguardCfg,
false);
}
/**
* Packages up the manifest with resources, and generates the R.java.
* @throws InterruptedException
*
* @deprecated in favor of {@link ApplicationManifest#packWithDataAndResources}.
*/
@Deprecated
public ResourceApk packWithResources(
Artifact resourceApk,
RuleContext ruleContext,
ResourceDependencies resourceDeps,
boolean createSource,
Artifact proguardCfg,
@Nullable Artifact mainDexProguardCfg) throws InterruptedException {
TransitiveInfoCollection resourcesPrerequisite =
ruleContext.getPrerequisite("resources", Mode.TARGET);
ResourceContainer resourceContainer = Iterables.getOnlyElement(
resourcesPrerequisite.getProvider(AndroidResourcesProvider.class)
.getDirectAndroidResources());
// It's ugly, but flattening now is more performant given the rest of the checks.
List<ResourceContainer> resourceContainers =
ImmutableList.<ResourceContainer>builder()
//.add(resourceContainer)
.addAll(resourceDeps.getResources()).build();
// Dealing with Android library projects
if (Iterables.size(resourceDeps.getResources()) > 1) {
if (resourceContainer.getConstantsInlined()
&& !resourceContainer.getArtifacts(ResourceType.RESOURCES).isEmpty()) {
ruleContext.ruleError("This android_binary depends on an android_library, so the"
+ " resources '" + AndroidCommon.getAndroidResources(ruleContext).getLabel()
+ "' should have the attribute inline_constants set to 0");
return null;
}
}
// This binary depends on a library project, so we need to regenerate the
// resources. The resulting sources and apk will combine all the resources
// contained in the transitive closure of the binary.
AndroidAaptActionHelper aaptActionHelper = new AndroidAaptActionHelper(ruleContext,
getManifest(), Lists.newArrayList(resourceContainers));
String resourceConfigurationFilters = ResourceConfigurationFilter.extractFilters(ruleContext);
List<String> uncompressedExtensions =
ruleContext.getTokenizedStringListAttr("nocompress_extensions");
ImmutableList.Builder<String> additionalAaptOpts = ImmutableList.<String>builder();
for (String extension : uncompressedExtensions) {
additionalAaptOpts.add("-0").add(extension);
}
if (!resourceConfigurationFilters.isEmpty()) {
additionalAaptOpts.add("-c").add(resourceConfigurationFilters);
}
Artifact javaSourcesJar = null;
if (createSource) {
javaSourcesJar =
ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_JAVA_SOURCE_JAR);
aaptActionHelper.createGenerateResourceSymbolsAction(
javaSourcesJar, null, resourceContainer.getJavaPackage(), true);
}
List<String> densities = ruleContext.getTokenizedStringListAttr("densities");
aaptActionHelper.createGenerateApkAction(resourceApk,
resourceContainer.getRenameManifestPackage(), additionalAaptOpts.build(), densities);
ResourceContainer updatedResources = resourceContainer.toBuilder()
.setLabel(ruleContext.getLabel())
.setApk(resourceApk)
.setManifest(getManifest())
.setJavaSourceJar(javaSourcesJar)
.setJavaClassJar(null)
.setSymbols(null)
.build();
aaptActionHelper.createGenerateProguardAction(proguardCfg, mainDexProguardCfg);
return new ResourceApk(resourceApk,
updatedResources.getJavaSourceJar(),
updatedResources.getJavaClassJar(),
resourceDeps, updatedResources, manifest, proguardCfg, mainDexProguardCfg, true);
}
public Artifact getManifest() {
return manifest;
}
}