Merge android_app_bundle.md into android_dynamic_feature_modules.md
These make more sense as one. Change-Id: I3fa6e52fbbf3d2cd83f87dea066d814371761e7b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3097706 Commit-Queue: Andrew Grieve <agrieve@chromium.org> Auto-Submit: Andrew Grieve <agrieve@chromium.org> Reviewed-by: Samuel Huang <huangs@chromium.org> Cr-Commit-Position: refs/heads/master@{#912697}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
d3ad25ace1
commit
7e777abf7e
build
chrome/android/modules
docs
@ -1,7 +1,7 @@
|
||||
# Android Build Docs
|
||||
|
||||
* [//docs/android_build_instructions.md](/docs/android_build_instructions.md)
|
||||
* [android_app_bundles.md](android_app_bundles.md)
|
||||
* [//docs/android_dynamic_feature_modules.md](/docs/android_dynamic_feature_modules.md)
|
||||
* [build_config.md](build_config.md)
|
||||
* [coverage.md](coverage.md)
|
||||
* [java_toolchain.md](java_toolchain.md)
|
||||
|
@ -1,205 +0,0 @@
|
||||
# Introduction
|
||||
|
||||
This document describes how the Chromium build system supports Android app
|
||||
bundles.
|
||||
|
||||
[TOC]
|
||||
|
||||
# Overview of app bundles
|
||||
|
||||
An Android app bundle is an alternative application distribution format for
|
||||
Android applications on the Google Play Store, that allows reducing the size
|
||||
of binaries sent for installation to individual devices that run on Android L
|
||||
and beyond. For more information about them, see the official Android
|
||||
[documentation](https://developer.android.com/guide/app-bundle/).
|
||||
|
||||
For the context of this document, the most important points are:
|
||||
|
||||
- Unlike a regular APK (e.g. `foo.apk`), the bundle (e.g. `foo.aab`) cannot
|
||||
be installed directly on a device.
|
||||
|
||||
- Instead, it must be processed into a set of installable split APKs, which
|
||||
are stored inside a special zip archive (e.g. `foo.apks`).
|
||||
|
||||
- The splitting can be based on various criteria: e.g. language or screen
|
||||
density for resources, or cpu ABI for native code.
|
||||
|
||||
- The bundle also uses the notion of dynamic features modules (DFMs) to
|
||||
separate several application features. Each module has its own code, assets
|
||||
and resources, and can be installed separately from the rest of the
|
||||
application if needed.
|
||||
|
||||
- The main application itself is stored in the '`base`' module (this name
|
||||
cannot be changed).
|
||||
|
||||
|
||||
# Declaring app bundles with GN templates
|
||||
|
||||
Here's an example that shows how to declare a simple bundle that contains a
|
||||
single base module, which enables language-based splits:
|
||||
|
||||
```gn
|
||||
|
||||
# First declare the first bundle module. The base module is the one
|
||||
# that contains the main application's code, resources and assets.
|
||||
android_app_bundle_module("foo_base_module") {
|
||||
# Declaration are similar to android_apk here.
|
||||
...
|
||||
}
|
||||
|
||||
# Second, declare the bundle itself.
|
||||
android_app_bundle("foo_bundle") {
|
||||
# Indicate the base module to use for this bundle
|
||||
base_module_target = ":foo_base_module"
|
||||
|
||||
# The name of our bundle file (without any suffix). Default would
|
||||
# be 'foo_bundle' otherwise.
|
||||
bundle_name = "FooBundle"
|
||||
|
||||
# Enable language-based splits for this bundle. Which means that
|
||||
# resources and assets specific to a given language will be placed
|
||||
# into their own split APK in the final .apks archive.
|
||||
enable_language_splits = true
|
||||
|
||||
# Proguard settings must be passed at the bundle, not module, target.
|
||||
proguard_enabled = !is_java_debug
|
||||
}
|
||||
```
|
||||
|
||||
When generating the `foo_bundle` target with Ninja, you will end up with
|
||||
the following:
|
||||
|
||||
- The bundle file under `out/Release/apks/FooBundle.aab`
|
||||
|
||||
- A helper script called `out/Release/bin/foo_bundle`, which can be used
|
||||
to install / launch / uninstall the bundle on local devices.
|
||||
|
||||
This works like an APK wrapper script (e.g. `foo_apk`). Use `--help`
|
||||
to see all possible commands supported by the script.
|
||||
|
||||
|
||||
# Declaring dynamic feature modules with GN templates
|
||||
|
||||
Please see
|
||||
[Dynamic Feature Modules](../../../docs/android_dynamic_feature_modules.md) for
|
||||
more details. In short, if you need more modules besides the base one, you
|
||||
will need to list all the extra ones using the extra_modules variable which
|
||||
takes a list of GN scopes, as in:
|
||||
|
||||
```gn
|
||||
|
||||
android_app_bundle_module("foo_base_module") {
|
||||
...
|
||||
}
|
||||
|
||||
android_app_bundle_module("foo_extra_module") {
|
||||
...
|
||||
}
|
||||
|
||||
android_app_bundle("foo_bundle") {
|
||||
base_module_target = ":foo_base_module"
|
||||
|
||||
extra_modules = [
|
||||
{ # NOTE: Scopes require one field per line, and no comma separators.
|
||||
name = "my_module"
|
||||
module_target = ":foo_extra_module"
|
||||
}
|
||||
]
|
||||
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Note that each extra module is identified by a unique name, which cannot
|
||||
be '`base`'.
|
||||
|
||||
|
||||
# Bundle signature issues
|
||||
|
||||
Signing an app bundle is not necessary, unless you want to upload it to the
|
||||
Play Store. Since this process is very slow (it uses `jarsigner` instead of
|
||||
the much faster `apkbuilder`), you can control it with the `sign_bundle`
|
||||
variable, as described in the example above.
|
||||
|
||||
The `.apks` archive however always contains signed split APKs. The keystore
|
||||
path/password/alias being used are the default ones, unless you use custom
|
||||
values when declaring the bundle itself, as in:
|
||||
|
||||
```gn
|
||||
android_app_bundle("foo_bundle") {
|
||||
...
|
||||
keystore_path = "//path/to/keystore"
|
||||
keystore_password = "K3y$t0Re-Pa$$w0rd"
|
||||
keystore_name = "my-signing-key-name"
|
||||
}
|
||||
```
|
||||
|
||||
These values are not stored in the bundle itself, but in the wrapper script,
|
||||
which will use them to generate the `.apks` archive for you. This allows you
|
||||
to properly install updates on top of existing applications on any device.
|
||||
|
||||
|
||||
# Proguard and bundles
|
||||
|
||||
When using an app bundle that is made of several modules, it is crucial to
|
||||
ensure that proguard, if enabled:
|
||||
|
||||
- Keeps the obfuscated class names used by each module consistent.
|
||||
- Does not remove classes that are not used in one module, but referenced
|
||||
by others.
|
||||
|
||||
To achieve this, a special scheme called *synchronized proguarding* is
|
||||
performed, which consists of the following steps:
|
||||
|
||||
- The list of unoptimized .jar files from all modules are sent to a single
|
||||
proguard command. This generates a new temporary optimized *group* .jar file.
|
||||
|
||||
- Each module extracts the optimized class files from the optimized *group*
|
||||
.jar file, to generate its own, module-specific, optimized .jar.
|
||||
|
||||
- Each module-specific optimized .jar is then sent to dex generation.
|
||||
|
||||
This synchronized proguarding step is added by the `android_app_bundle()` GN
|
||||
template. In practice this means the following:
|
||||
|
||||
- `proguard_enabled` must be passed to `android_app_bundle` targets, but not
|
||||
to `android_app_bundle_module` ones.
|
||||
|
||||
- `proguard_configs` can be still passed to individual modules, just
|
||||
like regular APKs. All proguard configs will be merged during the
|
||||
synchronized proguard step.
|
||||
|
||||
|
||||
# Manual generation and installation of .apks archives
|
||||
|
||||
Note that the `foo_bundle` script knows how to generate the .apks archive
|
||||
from the bundle file, and install it to local devices for you. For example,
|
||||
to install and launch a bundle, use:
|
||||
|
||||
```sh
|
||||
out/Release/bin/foo_bundle run
|
||||
```
|
||||
|
||||
If you want to manually look or use the `.apks` archive, use the following
|
||||
command to generate it:
|
||||
|
||||
```sh
|
||||
out/Release/bin/foo_bundle build-bundle-apks \
|
||||
--output-apks=/tmp/BundleFoo.apks
|
||||
```
|
||||
|
||||
All split APKs within the archive will be properly signed. And you will be
|
||||
able to look at its content (with `unzip -l`), or install it manually with:
|
||||
|
||||
```sh
|
||||
build/android/gyp/bundletool.py install-apks \
|
||||
--apks=/tmp/BundleFoo.apks \
|
||||
--adb=$(which adb)
|
||||
```
|
||||
|
||||
The task of examining the manifest is simplified by running the following,
|
||||
which dumps the application manifest as XML to stdout:
|
||||
|
||||
```sh
|
||||
build/android/gyp/bundletool.py dump-manifest
|
||||
```
|
@ -2884,8 +2884,7 @@ if (enable_java_templates) {
|
||||
}
|
||||
} else {
|
||||
# Dex generation for app bundle modules with proguarding enabled takes
|
||||
# place later due to synchronized proguarding. For more details,
|
||||
# read build/android/docs/android_app_bundles.md
|
||||
# place later due to synchronized proguarding.
|
||||
_final_dex_target_name = "${_template_name}__final_dex"
|
||||
dex(_final_dex_target_name) {
|
||||
forward_variables_from(invoker,
|
||||
|
@ -1,7 +1,6 @@
|
||||
# Chrome on Android App Bundles and Dynamic Feature Modules
|
||||
|
||||
This directory contains GN templates and code for Chrome-specific
|
||||
[Android app bundles](/build/android/docs/android_app_bundles.md) and
|
||||
[dynamic feature modules](/docs/android_dynamic_feature_modules.md).
|
||||
Among others, it offers the following:
|
||||
|
||||
|
@ -282,12 +282,9 @@ used when committed.
|
||||
Java related issues at compile time with the 'lint' tool.
|
||||
* [Java Code Coverage](../build/android/docs/coverage.md) - Collecting code
|
||||
coverage data with the EMMA tool.
|
||||
* [Android BuildConfig files](../build/android/docs/build_config.md) -
|
||||
What are .build_config files and how they are used.
|
||||
* [Android App Bundles](../build/android/docs/android_app_bundles.md) -
|
||||
How to build Android app bundles for Chrome.
|
||||
* [Dynamic Feature Modules (DFMs)](android_dynamic_feature_modules.md) - How
|
||||
to create dynamic feature modules.
|
||||
* [Dynamic Feature Modules (DFMs)](android_dynamic_feature_modules.md) - What
|
||||
are they and how to create new ones.
|
||||
* [Other build-related Android docs](../build/android/docs/index.md)
|
||||
* [Chrome for Android UI](ui/android/overview.md) - Resources and best practices for
|
||||
developing UI
|
||||
|
||||
|
@ -12,6 +12,8 @@ Bundles provide three main advantages over monolithic `.apk` files:
|
||||
1. Language resources are split into language-specific `.apk` files, known as
|
||||
"resource splits". Delivering only the active languages reduces the overhead
|
||||
of UI strings.
|
||||
* Resource splits can also be made on a per-screen-density basis (for drawables),
|
||||
but Chrome has not taken advantage of this (yet).
|
||||
2. Features can be packaged into lazily loaded `.apk` files, known as
|
||||
"feature splits". Feature splits have no performance overhead until used.
|
||||
* Except on versions prior to Android O, where support for
|
||||
@ -38,24 +40,57 @@ Adding new features vis feature splits is highly encouraged when it makes sense
|
||||
to do so:
|
||||
* Has a non-trivial amount of Dex (>50kb)
|
||||
* Not needed on startup
|
||||
* Has a small integration surface (calls into it must be done with reflection).
|
||||
* Has a small integration surface (calls into it must be done with reflection)
|
||||
* Not used by WebView (WebView does not support DFMs)
|
||||
***
|
||||
|
||||
The remainder of this doc focuses on DFMs.
|
||||
|
||||
[android_build_instructions.md#multiple-chrome-targets]: android_build_instructions.md#multiple-chrome-targets
|
||||
[Android App Bundles]: https://developer.android.com/guide/app-bundle
|
||||
[android:isolatedSplits]: https://developer.android.com/reference/android/R.attr#isolatedSplits
|
||||
[go/isolated-splits-dev-guide]: http://go/isolated-splits-dev-guide
|
||||
|
||||
## Limitations
|
||||
### Declaring App Bundles with GN Templates
|
||||
|
||||
DFMs have the following limitations:
|
||||
Here's an example that shows how to declare a simple bundle that contains a
|
||||
single base module, which enables language-based splits:
|
||||
|
||||
* **WebView:** We don't support DFMs for WebView. If your feature is used by
|
||||
WebView you cannot put it into a DFM.
|
||||
```gn
|
||||
android_app_bundle_module("foo_base_module") {
|
||||
# Declaration are similar to android_apk here.
|
||||
...
|
||||
}
|
||||
|
||||
## Getting started
|
||||
android_app_bundle("foo_bundle") {
|
||||
base_module_target = ":foo_base_module"
|
||||
|
||||
# The name of our bundle file (without any suffix).
|
||||
bundle_name = "FooBundle"
|
||||
|
||||
# Enable language-based splits for this bundle. Which means that
|
||||
# resources and assets specific to a given language will be placed
|
||||
# into their own split APK in the final .apks archive.
|
||||
enable_language_splits = true
|
||||
|
||||
# Proguard settings must be passed at the bundle, not module, target.
|
||||
proguard_enabled = !is_java_debug
|
||||
}
|
||||
```
|
||||
|
||||
When generating the `foo_bundle` target with Ninja, you will end up with
|
||||
the following:
|
||||
|
||||
* The bundle file under `out/Release/apks/FooBundle.aab`
|
||||
|
||||
* A helper script called `out/Release/bin/foo_bundle`, which can be used
|
||||
to install / launch / uninstall the bundle on local devices.
|
||||
|
||||
This works like an APK wrapper script (e.g. `foo_apk`). Use `--help`
|
||||
to see all possible commands supported by the script.
|
||||
|
||||
|
||||
The remainder of this doc focuses on DFMs.
|
||||
|
||||
## Declaring Dynamic Feature Modules (DFMs)
|
||||
|
||||
This guide walks you through the steps to create a DFM called _Foo_ and add it
|
||||
to the Chrome bundles.
|
||||
@ -207,6 +242,15 @@ $ adb shell dumpsys package org.chromium.chrome | grep splits
|
||||
> splits=[base, config.en]
|
||||
```
|
||||
|
||||
*** note
|
||||
The wrapper script's `install` command does approximately:
|
||||
```sh
|
||||
java -jar third_party/android_build_tools/bundletool/bundletool-all-$VERSION.jar build-apks --output tmp.apks ...
|
||||
java -jar third_party/android_build_tools/bundletool/bundletool-all-$VERSION.jar install-apks --apks tmp.apks
|
||||
```
|
||||
|
||||
The `install-apks` command uses `adb install-multiple` under-the-hood.
|
||||
***
|
||||
|
||||
### Adding Java code
|
||||
|
||||
|
Reference in New Issue
Block a user