Search in sources :

Example 91 with AndroidManifest

use of com.android.tools.build.bundletool.model.AndroidManifest in project bundletool by google.

the class BundleModuleMerger method mergeAndroidManifest.

private static void mergeAndroidManifest(Version bundletoolVersion, ImmutableSet<BundleModule> bundleModulesToFuse, BundleModule.Builder mergedBaseModule) {
    HashMultimap<BundleModuleName, AndroidManifest> manifests = bundleModulesToFuse.stream().collect(toMultimap(BundleModule::getName, BundleModule::getAndroidManifest, HashMultimap::create));
    AndroidManifestMerger manifestMerger = FUSE_APPLICATION_ELEMENTS_FROM_FEATURE_MANIFESTS.enabledForVersion(bundletoolVersion) ? fusingMergerApplicationElements() : fusingMergerOnlyReplaceActivities();
    AndroidManifest mergedManifest = manifestMerger.merge(manifests);
    mergedManifest = mergedManifest.toEditor().setFusedModuleNames(bundleModulesToFuse.stream().map(module -> module.getName().getName()).collect(toImmutableList())).save();
    mergedBaseModule.setAndroidManifest(mergedManifest);
}
Also used : BundleModuleName(com.android.tools.build.bundletool.model.BundleModuleName) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest)

Example 92 with AndroidManifest

use of com.android.tools.build.bundletool.model.AndroidManifest in project bundletool by google.

the class FusingAndroidManifestMerger method mergeManifests.

private AndroidManifest mergeManifests(AndroidManifest baseManifest, List<AndroidManifest> featureManifests) {
    // Gather all child elements of 'application' from all manifest. If element with the same name
    // and type is presented in more than one manifest we give precedency to one in feature module.
    // All feature manifests are sorted by feature module name in this method.
    ImmutableListMultimap<ApplicationElementId, XmlProtoElement> applicationElements = gatherApplicationElementsManifests(ImmutableList.<AndroidManifest>builder().addAll(featureManifests).add(baseManifest).build(), elementsToMerge);
    // This is optimization that allows to skip merging if there is no mergeable elements in
    // feature modules.
    long numberOfMergeableElementsInBase = baseManifest.getManifestRoot().getElement().getChildrenElements(AndroidManifest.APPLICATION_ELEMENT_NAME).flatMap(application -> application.getChildrenElements()).filter(element -> elementsToMerge.contains(element.getName())).count();
    if (numberOfMergeableElementsInBase == applicationElements.size()) {
        return baseManifest;
    }
    // Merge manifest elements with the same name and type based on specified mode.
    ImmutableMap<ApplicationElementId, XmlProtoElement> mergedElements = applicationElements.keySet().stream().collect(toImmutableMap(Function.identity(), key -> mergeElements(key, applicationElements.get(key))));
    ManifestEditor manifestEditor = baseManifest.toEditor();
    XmlProtoElementBuilder applicationElement = manifestEditor.getRawProto().getOrCreateChildElement(AndroidManifest.APPLICATION_ELEMENT_NAME);
    // Replace original elements from the base manifest with merged ones. This is done in a way to
    // preserve original elements ordering and additional elements are added to the end.
    Set<XmlProtoElement> replacedElements = Sets.newIdentityHashSet();
    applicationElement.modifyChildElements(child -> stream(getCorrespondingElementFromMergedElements(child, mergedElements)).peek(replacedElements::add).map(element -> XmlProtoNodeBuilder.createElementNode(element.toBuilder())).collect(toOptional()).orElse(child));
    mergedElements.values().stream().filter(not(replacedElements::contains)).forEach(element -> applicationElement.addChildElement(element.toBuilder()));
    return manifestEditor.save();
}
Also used : Iterables(com.google.common.collect.Iterables) BundleModuleName(com.android.tools.build.bundletool.model.BundleModuleName) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest) XmlProtoAttributeBuilder(com.android.tools.build.bundletool.model.utils.xmlproto.XmlProtoAttributeBuilder) BASE_MODULE_NAME(com.android.tools.build.bundletool.model.BundleModuleName.BASE_MODULE_NAME) Function(java.util.function.Function) Predicates.not(com.google.common.base.Predicates.not) ImmutableList(com.google.common.collect.ImmutableList) Map(java.util.Map) ImmutableSet.toImmutableSet(com.google.common.collect.ImmutableSet.toImmutableSet) XmlProtoNodeBuilder(com.android.tools.build.bundletool.model.utils.xmlproto.XmlProtoNodeBuilder) XmlProtoElement(com.android.tools.build.bundletool.model.utils.xmlproto.XmlProtoElement) MoreCollectors.toOptional(com.google.common.collect.MoreCollectors.toOptional) XmlProtoElementBuilder(com.android.tools.build.bundletool.model.utils.xmlproto.XmlProtoElementBuilder) ImmutableSet(com.google.common.collect.ImmutableSet) ImmutableMap(com.google.common.collect.ImmutableMap) CommandExecutionException(com.android.tools.build.bundletool.model.exceptions.CommandExecutionException) ImmutableList.toImmutableList(com.google.common.collect.ImmutableList.toImmutableList) Set(java.util.Set) SetMultimap(com.google.common.collect.SetMultimap) Sets(com.google.common.collect.Sets) Streams.stream(com.google.common.collect.Streams.stream) ImmutableMap.toImmutableMap(com.google.common.collect.ImmutableMap.toImmutableMap) List(java.util.List) ImmutableListMultimap(com.google.common.collect.ImmutableListMultimap) AutoValue(com.google.auto.value.AutoValue) Optional(java.util.Optional) ManifestEditor(com.android.tools.build.bundletool.model.ManifestEditor) Comparator(java.util.Comparator) XmlProtoElementBuilder(com.android.tools.build.bundletool.model.utils.xmlproto.XmlProtoElementBuilder) ManifestEditor(com.android.tools.build.bundletool.model.ManifestEditor) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest) XmlProtoElement(com.android.tools.build.bundletool.model.utils.xmlproto.XmlProtoElement)

Example 93 with AndroidManifest

use of com.android.tools.build.bundletool.model.AndroidManifest in project bundletool by google.

the class ModuleSplitsToShardMerger method mergeSingleShard.

/**
 * Gets a list of splits, and merges them into a single standalone APK (aka shard).
 *
 * <p>Allows to customize split type {@code mergedSplitType} of merged shard and Android manifest
 * merger {@code manifestMerger}.
 */
public ModuleSplit mergeSingleShard(ImmutableCollection<ModuleSplit> splitsOfShard, Map<ImmutableSet<ModuleEntry>, ImmutableList<Path>> mergedDexCache, SplitType mergedSplitType, AndroidManifestMerger manifestMerger) {
    ListMultimap<BundleModuleName, ModuleEntry> dexFilesToMergeByModule = ArrayListMultimap.create();
    // If multiple splits were generated from one module, we'll see the same manifest multiple
    // times. The multimap filters out identical (module name, manifest) pairs by contract.
    // All splits of a module should have the same manifest, so the following multimap should
    // associate just one value with each key. This is checked explicitly for the base module
    // because the manifest merger requires *single* base manifest.
    SetMultimap<BundleModuleName, AndroidManifest> androidManifestsToMergeByModule = HashMultimap.create();
    Map<ZipPath, ModuleEntry> mergedEntriesByPath = new HashMap<>();
    Optional<ResourceTable> mergedResourceTable = Optional.empty();
    Map<String, TargetedAssetsDirectory> mergedAssetsConfig = new HashMap<>();
    ApkTargeting mergedSplitTargeting = ApkTargeting.getDefaultInstance();
    for (ModuleSplit split : splitsOfShard) {
        // Resource tables and Split targetings can be merged for each split individually as we go.
        mergedResourceTable = mergeResourceTables(mergedResourceTable, split);
        mergedSplitTargeting = mergeSplitTargetings(mergedSplitTargeting, split);
        // Android manifests need to be merged later, globally for all splits.
        androidManifestsToMergeByModule.put(split.getModuleName(), split.getAndroidManifest());
        for (ModuleEntry entry : split.getEntries()) {
            if (entry.getPath().startsWith(DEX_DIRECTORY)) {
                // Dex files need to be merged later, globally for all splits.
                dexFilesToMergeByModule.put(split.getModuleName(), entry);
            } else {
                mergeEntries(mergedEntriesByPath, split, entry);
            }
        }
        split.getAssetsConfig().ifPresent(assetsConfig -> {
            mergeTargetedAssetsDirectories(mergedAssetsConfig, assetsConfig.getDirectoryList());
        });
    }
    AndroidManifest mergedAndroidManifest = manifestMerger.merge(androidManifestsToMergeByModule);
    Collection<ModuleEntry> mergedDexFiles = mergeDexFilesAndCache(dexFilesToMergeByModule, mergedAndroidManifest, mergedDexCache);
    // Record names of the modules this shard was fused from.
    ImmutableList<String> fusedModuleNames = getUniqueModuleNames(splitsOfShard);
    if (mergedSplitType.equals(SplitType.STANDALONE)) {
        mergedAndroidManifest = mergedAndroidManifest.toEditor().setFusedModuleNames(fusedModuleNames).save();
    }
    // Construct the final shard.
    return buildShard(mergedEntriesByPath.values(), mergedDexFiles, mergedSplitTargeting, mergedAndroidManifest, mergedResourceTable, mergedAssetsConfig, mergedSplitType);
}
Also used : BundleModuleName(com.android.tools.build.bundletool.model.BundleModuleName) TargetedAssetsDirectory(com.android.bundle.Files.TargetedAssetsDirectory) ApkTargeting(com.android.bundle.Targeting.ApkTargeting) HashMap(java.util.HashMap) ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry) ModuleSplit(com.android.tools.build.bundletool.model.ModuleSplit) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest) ZipPath(com.android.tools.build.bundletool.model.ZipPath) ResourceTable(com.android.aapt.Resources.ResourceTable)

Example 94 with AndroidManifest

use of com.android.tools.build.bundletool.model.AndroidManifest in project bundletool by google.

the class SameTargetingMerger method mergeSplits.

private ModuleSplit mergeSplits(ImmutableCollection<ModuleSplit> splits) {
    ModuleSplit.Builder builder = ModuleSplit.builder();
    ImmutableList.Builder<ModuleEntry> entries = ImmutableList.builder();
    AndroidManifest mergedManifest = null;
    ResourceTable mergedResourceTable = null;
    NativeLibraries mergedNativeConfig = null;
    Map<String, TargetedAssetsDirectory> mergedAssetsConfig = new HashMap<>();
    ApexImages mergedApexConfig = null;
    ImmutableList<ApexEmbeddedApkConfig> mergedApexEmbeddedApkConfigs = null;
    BundleModuleName mergedModuleName = null;
    Boolean mergedIsMasterSplit = null;
    VariantTargeting mergedVariantTargeting = null;
    for (ModuleSplit split : splits) {
        mergedManifest = getSameValueOrNonNull(mergedManifest, split.getAndroidManifest()).orElseThrow(() -> new IllegalStateException("Encountered two distinct manifests while merging."));
        if (split.getResourceTable().isPresent()) {
            mergedResourceTable = getSameValueOrNonNull(mergedResourceTable, split.getResourceTable().get()).orElseThrow(() -> new IllegalStateException("Unsupported case: encountered two distinct resource tables while " + "merging."));
        }
        if (split.getNativeConfig().isPresent()) {
            mergedNativeConfig = getSameValueOrNonNull(mergedNativeConfig, split.getNativeConfig().get()).orElseThrow(() -> new IllegalStateException("Encountered two distinct native configs while merging."));
        }
        if (split.getApexConfig().isPresent()) {
            mergedApexConfig = getSameValueOrNonNull(mergedApexConfig, split.getApexConfig().get()).orElseThrow(() -> new IllegalStateException("Encountered two distinct apex configs while merging."));
        }
        mergedApexEmbeddedApkConfigs = getSameValueOrNonNull(mergedApexEmbeddedApkConfigs, split.getApexEmbeddedApkConfigs()).orElseThrow(() -> new IllegalStateException("Encountered two distinct apex embedded apk configs while merging."));
        mergedModuleName = getSameValueOrNonNull(mergedModuleName, split.getModuleName()).orElseThrow(() -> new IllegalStateException("Encountered two distinct module names while merging."));
        mergedIsMasterSplit = getSameValueOrNonNull(mergedIsMasterSplit, Boolean.valueOf(split.isMasterSplit())).orElseThrow(() -> new IllegalStateException("Encountered conflicting isMasterSplit flag values while merging."));
        mergedVariantTargeting = getSameValueOrNonNull(mergedVariantTargeting, split.getVariantTargeting()).orElseThrow(() -> new IllegalStateException("Encountered conflicting variant targeting values while merging."));
        entries.addAll(split.getEntries());
        builder.setApkTargeting(split.getApkTargeting());
        split.getAssetsConfig().ifPresent(assetsConfig -> {
            mergeTargetedAssetsDirectories(mergedAssetsConfig, assetsConfig.getDirectoryList());
        });
    }
    if (mergedManifest != null) {
        builder.setAndroidManifest(mergedManifest);
    }
    if (mergedResourceTable != null) {
        builder.setResourceTable(mergedResourceTable);
    }
    if (mergedNativeConfig != null) {
        builder.setNativeConfig(mergedNativeConfig);
    }
    if (!mergedAssetsConfig.isEmpty()) {
        builder.setAssetsConfig(Assets.newBuilder().addAllDirectory(mergedAssetsConfig.values()).build());
    }
    if (mergedApexConfig != null) {
        builder.setApexConfig(mergedApexConfig);
    }
    if (mergedApexEmbeddedApkConfigs != null) {
        builder.setApexEmbeddedApkConfigs(mergedApexEmbeddedApkConfigs);
    }
    if (mergedModuleName != null) {
        builder.setModuleName(mergedModuleName);
    }
    if (mergedIsMasterSplit != null) {
        builder.setMasterSplit(mergedIsMasterSplit);
    }
    builder.setVariantTargeting(mergedVariantTargeting);
    builder.setEntries(entries.build());
    return builder.build();
}
Also used : ApexImages(com.android.bundle.Files.ApexImages) BundleModuleName(com.android.tools.build.bundletool.model.BundleModuleName) TargetedAssetsDirectory(com.android.bundle.Files.TargetedAssetsDirectory) NativeLibraries(com.android.bundle.Files.NativeLibraries) HashMap(java.util.HashMap) ImmutableList(com.google.common.collect.ImmutableList) ModuleEntry(com.android.tools.build.bundletool.model.ModuleEntry) ModuleSplit(com.android.tools.build.bundletool.model.ModuleSplit) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest) ApexEmbeddedApkConfig(com.android.bundle.Config.ApexEmbeddedApkConfig) VariantTargeting(com.android.bundle.Targeting.VariantTargeting) ResourceTable(com.android.aapt.Resources.ResourceTable)

Example 95 with AndroidManifest

use of com.android.tools.build.bundletool.model.AndroidManifest in project bundletool by google.

the class ManifestProtoUtilsTest method splitNameAttributeAddedToProvider.

@Test
public void splitNameAttributeAddedToProvider() {
    AndroidManifest manifest = AndroidManifest.create(androidManifest("com.test.app", withSplitNameProvider("FooProvider", "foo")));
    ImmutableList<XmlElement> providers = manifest.getManifestRoot().getElement().getChildElement("application").getChildrenElements(PROVIDER_ELEMENT_NAME).map(XmlProtoElement::getProto).collect(toImmutableList());
    assertThat(providers).hasSize(1);
    XmlElement providerElement = Iterables.getOnlyElement(providers);
    assertThat(providerElement.getAttributeList()).containsExactly(xmlAttribute(ANDROID_NAMESPACE_URI, NAME_ATTRIBUTE_NAME, NAME_RESOURCE_ID, "FooProvider"), xmlAttribute(ANDROID_NAMESPACE_URI, SPLIT_NAME_ATTRIBUTE_NAME, SPLIT_NAME_RESOURCE_ID, "foo"));
}
Also used : XmlElement(com.android.aapt.Resources.XmlElement) AndroidManifest(com.android.tools.build.bundletool.model.AndroidManifest) Test(org.junit.Test)

Aggregations

AndroidManifest (com.android.tools.build.bundletool.model.AndroidManifest)130 Test (org.junit.Test)115 ImmutableList (com.google.common.collect.ImmutableList)94 AppBundleBuilder (com.android.tools.build.bundletool.testing.AppBundleBuilder)90 ManifestProtoUtils.androidManifest (com.android.tools.build.bundletool.testing.ManifestProtoUtils.androidManifest)89 Truth.assertThat (com.google.common.truth.Truth.assertThat)89 RunWith (org.junit.runner.RunWith)89 ImmutableSet (com.google.common.collect.ImmutableSet)87 AppBundle (com.android.tools.build.bundletool.model.AppBundle)84 ApkTargeting (com.android.bundle.Targeting.ApkTargeting)82 Assertions.assertThrows (org.junit.jupiter.api.Assertions.assertThrows)81 VariantTargeting (com.android.bundle.Targeting.VariantTargeting)80 ZipPath (com.android.tools.build.bundletool.model.ZipPath)80 ImmutableList.toImmutableList (com.google.common.collect.ImmutableList.toImmutableList)79 ImmutableSet.toImmutableSet (com.google.common.collect.ImmutableSet.toImmutableSet)79 Path (java.nio.file.Path)79 AppBundleSerializer (com.android.tools.build.bundletool.io.AppBundleSerializer)78 Files (java.nio.file.Files)78 Before (org.junit.Before)78 Rule (org.junit.Rule)78