use of com.android.tools.build.bundletool.model.AppBundle in project bundletool by google.
the class BuildApksCommand method execute.
public Path execute() {
validateInput();
Path outputDirectory = getOutputFormat().equals(APK_SET) ? getOutputFile().getParent() : getOutputFile();
if (outputDirectory != null && Files.notExists(outputDirectory)) {
logger.info("Output directory '" + outputDirectory + "' does not exist, creating it.");
FileUtils.createDirectories(outputDirectory);
}
try (TempDirectory tempDir = new TempDirectory(getClass().getSimpleName())) {
Path bundlePath;
// The old APK serializer relies on the compression of entries in the App Bundle.
// Unfortunately, we don't know the compression level that was used when the bundle was built,
// so we re-compress all entries with our desired compression level.
// Exception is made when the device spec is specified, we only need a fraction of the
// entries, so re-compressing all entries would be a waste of CPU.
boolean recompressAppBundle = !getDeviceSpec().isPresent() && !getEnableApkSerializerWithoutBundleRecompression();
if (recompressAppBundle) {
bundlePath = tempDir.getPath().resolve("recompressed.aab");
new AppBundleRecompressor(getExecutorService()).recompressAppBundle(getBundlePath().toFile(), bundlePath.toFile());
} else {
bundlePath = getBundlePath();
}
try (ZipFile bundleZip = new ZipFile(bundlePath.toFile());
ZipReader zipReader = ZipReader.createFromFile(bundlePath);
Closer closer = Closer.create()) {
AppBundleValidator bundleValidator = AppBundleValidator.create(getExtraValidators());
bundleValidator.validateFile(bundleZip);
AppBundle appBundle = AppBundle.buildFromZip(bundleZip);
bundleValidator.validate(appBundle);
validateSdkBundles(closer);
AppBundlePreprocessorManager appBundlePreprocessorManager = DaggerAppBundlePreprocessorComponent.builder().setBuildApksCommand(this).build().create();
AppBundle preprocessedAppBundle = appBundlePreprocessorManager.processAppBundle(appBundle);
BuildApksManager buildApksManager = DaggerBuildApksManagerComponent.builder().setBuildApksCommand(this).setTempDirectory(tempDir).setAppBundle(preprocessedAppBundle).setZipReader(zipReader).setUseBundleCompression(recompressAppBundle).build().create();
buildApksManager.execute();
} catch (ZipException e) {
throw InvalidBundleException.builder().withCause(e).withUserMessage("The App Bundle is not a valid zip file.").build();
} finally {
if (isExecutorServiceCreatedByBundleTool()) {
getExecutorService().shutdown();
}
}
} catch (IOException e) {
throw new UncheckedIOException("An error occurred when processing the App Bundle.", e);
}
return getOutputFile();
}
use of com.android.tools.build.bundletool.model.AppBundle in project bundletool by google.
the class BuildApksManager method execute.
public void execute() throws IOException {
ImmutableSet<BundleModuleName> permanentlyFusedModules = ImmutableSet.of();
ImmutableSet<BundleModule> requestedModules = command.getModules().isEmpty() ? ImmutableSet.of() : ModuleDependenciesUtils.getModulesIncludingDependencies(appBundle, getBundleModules(appBundle, command.getModules()));
GeneratedApks.Builder generatedApksBuilder = GeneratedApks.builder();
GeneratedAssetSlices.Builder generatedAssetSlices = GeneratedAssetSlices.builder();
boolean enableUniversalAsFallbackForSplits = false;
boolean enableInstallTimeNonRemovableModules = false;
ApksToGenerate apksToGenerate = new ApksToGenerate(appBundle, command.getApkBuildMode(), enableUniversalAsFallbackForSplits, deviceSpec);
// Split APKs
if (apksToGenerate.generateSplitApks()) {
AppBundle mergedAppBundle = BundleModuleMerger.mergeNonRemovableInstallTimeModules(appBundle, enableInstallTimeNonRemovableModules);
AppBundleValidator bundleValidator = AppBundleValidator.create(command.getExtraValidators());
bundleValidator.validate(mergedAppBundle);
generatedApksBuilder.setSplitApks(generateSplitApks(mergedAppBundle));
permanentlyFusedModules = Sets.difference(appBundle.getModules().keySet(), mergedAppBundle.getModules().keySet()).immutableCopy();
}
// Instant APKs
if (apksToGenerate.generateInstantApks()) {
generatedApksBuilder.setInstantApks(generateInstantApks(appBundle));
}
// Standalone APKs
if (apksToGenerate.generateStandaloneApks()) {
generatedApksBuilder.setStandaloneApks(generateStandaloneApks(appBundle));
}
// Universal APK
if (apksToGenerate.generateUniversalApk()) {
// Note: Universal APK is a special type of standalone, with no optimization dimensions.
ImmutableList<BundleModule> modulesToFuse = requestedModules.isEmpty() ? modulesToFuse(getModulesForStandaloneApks(appBundle)) : requestedModules.asList();
generatedApksBuilder.setStandaloneApks(shardedApksFacade.generateSplits(modulesToFuse, ApkOptimizations.getOptimizationsForUniversalApk()));
}
// System APKs
if (apksToGenerate.generateSystemApks()) {
generatedApksBuilder.setSystemApks(generateSystemApks(appBundle, requestedModules));
}
// Archived APKs
if (apksToGenerate.generateArchivedApks()) {
generatedApksBuilder.setArchivedApks(generateArchivedApks(appBundle));
}
// Asset Slices
if (apksToGenerate.generateAssetSlices()) {
generatedAssetSlices.setAssetSlices(generateAssetSlices(appBundle));
}
// Populate alternative targeting based on variant targeting of all APKs.
GeneratedApks generatedApks = AlternativeVariantTargetingPopulator.populateAlternativeVariantTargeting(generatedApksBuilder.build(), appBundle.isAssetOnly() ? Optional.empty() : appBundle.getBaseModule().getAndroidManifest().getMaxSdkVersion());
// A variant is a set of APKs. One device is guaranteed to receive only APKs from the same. This
// is why we are processing new entries like split.xml for each variant separately.
generatedApks = GeneratedApks.fromModuleSplits(generatedApks.getAllApksGroupedByOrderedVariants().asMap().entrySet().stream().map(keySplit -> {
SplitsXmlInjector splitsXmlInjector = new SplitsXmlInjector();
ImmutableList<ModuleSplit> moduleSplits = splitsXmlInjector.process(keySplit.getKey(), keySplit.getValue());
LocaleConfigXmlInjector localeConfigXmlInjector = new LocaleConfigXmlInjector();
moduleSplits = localeConfigXmlInjector.process(keySplit.getKey(), moduleSplits);
return moduleSplits;
}).flatMap(Collection::stream).collect(toImmutableList()));
if (deviceSpec.isPresent()) {
// It is easier to fully check device compatibility once the splits have been generated (in
// memory). Note that no costly I/O happened up until this point, so it's not too late for
// this check.
checkDeviceCompatibilityWithBundle(generatedApks, deviceSpec.get());
}
if (command.getOverwriteOutput() && Files.exists(command.getOutputFile())) {
MoreFiles.deleteRecursively(command.getOutputFile(), RecursiveDeleteOption.ALLOW_INSECURE);
}
// Create variants and serialize APKs.
apkSerializerManager.serializeApkSet(createApkSetWriter(tempDir.getPath()), generatedApks, generatedAssetSlices.build(), deviceSpec, getLocalTestingInfo(appBundle), permanentlyFusedModules);
}
use of com.android.tools.build.bundletool.model.AppBundle in project bundletool by google.
the class BundleConfigValidatorTest method optimizations_tcfDimensionSuffixStrippingWithInvalidDefault_throws.
@Test
public void optimizations_tcfDimensionSuffixStrippingWithInvalidDefault_throws() throws Exception {
AppBundle appBundle = createAppBundle(BundleConfigBuilder.create().clearOptimizations().addSplitDimension(SplitDimension.newBuilder().setValueValue(Value.TEXTURE_COMPRESSION_FORMAT_VALUE).setSuffixStripping(SuffixStripping.newBuilder().setEnabled(true).setDefaultSuffix("unrecognized_tcf")).build()));
InvalidBundleException exception = assertThrows(InvalidBundleException.class, () -> new BundleConfigValidator().validateBundle(appBundle));
assertThat(exception).hasMessageThat().contains("The default texture compression format chosen for suffix stripping" + " (\"unrecognized_tcf\") is not valid.");
}
use of com.android.tools.build.bundletool.model.AppBundle in project bundletool by google.
the class BundleConfigValidatorTest method optimizations_duplicateSplitDimensions_positiveAndNegative_throws.
@Test
public void optimizations_duplicateSplitDimensions_positiveAndNegative_throws() throws Exception {
AppBundle appBundle = createAppBundle(BundleConfigBuilder.create().clearOptimizations().addSplitDimension(SplitDimension.Value.ABI, /* negate= */
false).addSplitDimension(SplitDimension.Value.ABI, /* negate= */
true));
InvalidBundleException exception = assertThrows(InvalidBundleException.class, () -> new BundleConfigValidator().validateBundle(appBundle));
assertThat(exception).hasMessageThat().contains("duplicate split dimensions");
}
use of com.android.tools.build.bundletool.model.AppBundle in project bundletool by google.
the class BundleConfigValidatorTest method optimizations_nonTcfDimensionsSuffixStrippingDisabled_ok.
@Test
public void optimizations_nonTcfDimensionsSuffixStrippingDisabled_ok() throws Exception {
AppBundle appBundle = createAppBundle(BundleConfigBuilder.create().clearOptimizations().addSplitDimension(SplitDimension.newBuilder().setValueValue(Value.LANGUAGE_VALUE).setSuffixStripping(SuffixStripping.newBuilder().setEnabled(false)).build()));
new BundleConfigValidator().validateBundle(appBundle);
}
Aggregations