Skip to content

Commit

Permalink
Prepare for release 1.11.2.
Browse files Browse the repository at this point in the history
  • Loading branch information
Iurii Makhno committed Sep 7, 2022
1 parent 0583e1f commit 2925ca4
Show file tree
Hide file tree
Showing 29 changed files with 884 additions and 897 deletions.
23 changes: 19 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
# bundletool

Bundletool is a tool to manipulate Android App Bundles.
Bundletool is a tool to manipulate Android App Bundles and Android SDK Bundles.

The **Android App Bundle** is a new format for publishing Android apps in app
distribution stores such as Google Play.
The **Android App Bundle** is a
[format](https://developer.android.com/guide/app-bundle/app-bundle-format) for
publishing Android apps in app distribution stores such as Google Play.

The **Android SDK Bundle** is a
[format](https://developer.android.com/studio/command-line/bundletool#asb-format)
for publishing
[runtime-enabled SDKs](https://developer.android.com/design-for-safety/privacy-sandbox/sdk-runtime)
to SDK distribution platforms such as Google Play SDK Console.

Bundletool has a few different responsibilities:

Expand All @@ -23,6 +30,14 @@ Bundletool has a few different responsibilities:
* **Verify code transparency** inside an Android App Bundle, APK files or an
application installed on a connected device.

* **Build an Android SDK Bundle** from a pre-compiled module of a project.

* **Generate an APK Set archive** containing the SDK APKs for all devices.

* **Generate an
[Android SDK archive](https://developer.android.com/studio/command-line/bundletool#asar-format)**,
a Maven-friendly representation of an Android SDK Bundle.

Read more about the App Bundle format and Bundletool's usage at
[g.co/androidappbundle](https://g.co/androidappbundle)

Expand All @@ -31,4 +46,4 @@ https://developer.android.com/studio/command-line/bundletool

## Releases

Latest release: [1.11.1](https://github.com/google/bundletool/releases)
Latest release: [1.11.2](https://github.com/google/bundletool/releases)
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
release_version = 1.11.1
release_version = 1.11.2
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;

import com.android.bundle.Targeting.SdkRuntimeTargeting;
import com.android.tools.build.bundletool.io.ApkSerializerManager;
import com.android.tools.build.bundletool.io.ApkSetWriter;
import com.android.tools.build.bundletool.io.TempDirectory;
Expand Down Expand Up @@ -90,7 +91,6 @@ private ImmutableList<ModuleSplit> generateSdkApks() {
return moduleSplitterForShards
.generateSplits(sdkBundle.getModule(), apkOptimizations.getStandaloneDimensions())
.stream()
.map(StandaloneApksGenerator::setVariantTargetingAndSplitType)
.map(moduleSplit -> moduleSplit.writeSdkVersionName(sdkBundle.getVersionName()))
.map(moduleSplit -> moduleSplit.writeSdkVersionCode(sdkBundle.getVersionCode().get()))
.map(moduleSplit -> moduleSplit.writeManifestPackage(sdkBundle.getManifestPackageName()))
Expand All @@ -102,6 +102,8 @@ private ImmutableList<ModuleSplit> generateSdkApks() {
.map(moduleSplit -> moduleSplit.writePatchVersion(sdkBundle.getPatchVersion()))
.map(moduleSplit -> moduleSplit.writeSdkProviderClassName(sdkBundle.getProviderClassName()))
.map(this::writeCompatSdkProviderClassNameIfPresent)
.map(StandaloneApksGenerator::setVariantTargetingAndSplitType)
.map(this::addSdkRuntimeTargeting)
.collect(toImmutableList());
}

Expand All @@ -112,4 +114,14 @@ private ModuleSplit writeCompatSdkProviderClassNameIfPresent(ModuleSplit moduleS
}
return moduleSplit;
}

private ModuleSplit addSdkRuntimeTargeting(ModuleSplit moduleSplit) {
return moduleSplit.toBuilder()
.setVariantTargeting(
moduleSplit.getVariantTargeting().toBuilder()
.setSdkRuntimeTargeting(
SdkRuntimeTargeting.newBuilder().setRequiresSdkRuntime(true))
.build())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public boolean matchesTargeting(DeviceGroupModuleTargeting targetingValue) {

@Override
protected boolean isDeviceDimensionPresent() {
return !getDeviceSpec().getDeviceGroupsList().isEmpty();
// Always true, because groups empty list is considered present.
return true;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ public Predicate<VariantTargeting> getVariantTargetingPredicate() {
* fail the matching.
*/
public Predicate<ModuleTargeting> getModuleTargetingPredicate() {
return Predicates.compose(this::matchesTargeting, this::getTargetingValue);
return Predicates.compose(
targetingValue -> !isDeviceDimensionPresent() || matchesTargeting(targetingValue),
this::getTargetingValue);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static com.android.tools.build.bundletool.model.ModuleDeliveryType.ALWAYS_INITIAL_INSTALL;
import static com.android.tools.build.bundletool.model.ModuleDeliveryType.CONDITIONAL_INITIAL_INSTALL;
import static com.android.tools.build.bundletool.model.ModuleDeliveryType.NO_INITIAL_INSTALL;
import static com.android.tools.build.bundletool.model.utils.Versions.ANDROID_T_API_VERSION;
import static com.android.tools.build.bundletool.model.version.VersionGuardedFeature.NAMESPACE_ON_INCLUDE_ATTRIBUTE_REQUIRED;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
Expand Down Expand Up @@ -138,7 +139,7 @@ public abstract class AndroidManifest {
public static final String COMPAT_SDK_PROVIDER_CLASS_NAME_ATTRIBUTE_NAME =
"android.sdksandbox.PROPERTY_COMPAT_SDK_PROVIDER_CLASS_NAME";
public static final String REQUIRED_ATTRIBUTE_NAME = "required";
public static final Integer SDK_SANDBOX_MIN_VERSION = 32;
public static final int SDK_SANDBOX_MIN_VERSION = ANDROID_T_API_VERSION;
public static final String USES_SDK_LIBRARY_ELEMENT_NAME = "uses-sdk-library";
public static final String CERTIFICATE_DIGEST_ATTRIBUTE_NAME = "certDigest";
public static final String TARGET_SANDBOX_VERSION_ATTRIBUTE_NAME = "targetSandboxVersion";
Expand Down Expand Up @@ -229,7 +230,7 @@ public abstract class AndroidManifest {
abstract Version getBundleToolVersion();

@Memoized
XmlProtoElement getManifestElement() {
public XmlProtoElement getManifestElement() {
return getManifestRoot().getElement();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,11 @@ public Builder addRawModules(Collection<BundleModule> bundleModules) {
return this;
}

public Builder addRawModule(BundleModule bundleModule) {
modulesBuilder().put(bundleModule.getName(), bundleModule);
return this;
}

public abstract Builder setMasterPinnedResourceIds(ImmutableSet<ResourceId> pinnedResourceIds);

public abstract Builder setMasterPinnedResourceNames(ImmutableSet<String> pinnedResourceNames);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ public boolean isFeatureModule() {
/** Version of Bundeltool used to build the bundle that this module belongs to. */
public abstract Version getBundletoolVersion();

abstract XmlNode getAndroidManifestProto();
public abstract XmlNode getAndroidManifestProto();

@Memoized
public AndroidManifest getAndroidManifest() {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/*
* Copyright (C) 2022 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.tools.build.bundletool.model;

import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;

import com.google.common.collect.ImmutableList;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
* Mutator of the name of dex files to workaround a Gradle plugin bug that creates a bundle with a
* dex file named "classes1.dex" instead of "classes2.dex".
*
* <p>This will be removed as soon as Gradle plugin bug is fixed.
*/
public class ClassesDexSanitizer extends ModuleEntriesMutator {

private static final Pattern CLASSES_DEX_REGEX_PATTERN =
Pattern.compile("dex/classes(\\d*)\\.dex");

@Override
public Predicate<ModuleEntry> getFilter() {
return entry -> entry.getPath().toString().matches(CLASSES_DEX_REGEX_PATTERN.pattern());
}

@Override
public Function<ImmutableList<ModuleEntry>, ImmutableList<ModuleEntry>> getMutator() {
return (dexEntries) ->
dexEntries.stream()
.map(ClassesDexSanitizer::sanitizeDexEntryName)
.collect(toImmutableList());
}

@Override
public boolean shouldApplyMutation(BundleModule module) {
return module.getEntry(ZipPath.create("dex/classes1.dex")).isPresent();
}

private static ModuleEntry sanitizeDexEntryName(ModuleEntry dexEntry) {
ZipPath sanitizedEntryPath = incrementClassesDexNumber(dexEntry.getPath());
return dexEntry.toBuilder().setPath(sanitizedEntryPath).build();
}

/**
* Increment the suffix of multidex files.
*
* <pre>
* dex/classes.dex -- dex/classes.dex
* dex/classes1.dex -- dex/classes2.dex
* dex/classes2.dex -- dex/classes3.dex
* </pre>
*/
private static ZipPath incrementClassesDexNumber(ZipPath entryPath) {
int num = getClassesIndexForDexPath(entryPath);
if (num == 0) {
return entryPath; // dex/classes.dex
}
return ZipPath.create("dex/classes" + (num + 1) + ".dex");
}

private static int getClassesIndexForDexPath(ZipPath entryPath) {
String fileName = entryPath.toString();

Matcher matcher = CLASSES_DEX_REGEX_PATTERN.matcher(fileName);
checkState(matcher.matches());

String num = matcher.group(1);
if (num.isEmpty()) {
return 0; // dex/classes.dex
}
return Integer.parseInt(num);
}
}
Loading

0 comments on commit 2925ca4

Please sign in to comment.