blob: 81d38be4f7c3be3771121739dda602e774b5d13a [file] [log] [blame] [view]
David 'Digit' Turner90944742018-08-03 13:22:081# Introduction
2
3This document describes how the Chromium build system supports Android app
4bundles.
5
6[TOC]
7
8# Overview of app bundles
9
10An Android app bundle is an alternative application distribution format for
11Android applications on the Google Play Store, that allows reducing the size
12of binaries sent for installation to individual devices that run on Android L
13and beyond. For more information about them, see the official Android
14documentation at:
15
16 https://developer.android.com/guide/app-bundle/
17
18For the context of this document, the most important points are:
19
20 - Unlike a regular APK (e.g. `foo.apk`), the bundle (e.g. `foo.aab`) cannot
21 be installed directly on a device.
22
23 - Instead, it must be processed into a set of installable split APKs, which
24 are stored inside a special zip archive (e.g. `foo.apks`).
25
26 - The splitting can be based on various criteria: e.g. language or screen
27 density for resources, or cpu ABI for native code.
28
29 - The bundle also uses the notion of modules to separate several application
30 features. Each module has its own code, assets and resources, and can be
31 installed separately from the rest of the application if needed.
32
33 - The main application itself is stored in the '`base`' module (this name
34 cannot be changed).
35
36
37# Declaring app bundles with GN templates
38
39Here's an example that shows how to declare a simple bundle that contains
40a single base module, which enables language-based splits:
41
42```gn
43
44 # First declare the first bundle module. The base module is the one
45 # that contains the main application's code, resources and assets.
46 android_app_bundle_module("foo_base_module") {
47 # Declaration are similar to android_apk here.
48 ...
49 }
50
51 # Second, declare the bundle itself.
52 android_app_bundle("foo_bundle") {
53 # Indicate the base module to use for this bundle
54 base_module_target = ":foo_base_module"
55
56 # The name of our bundle file (without any suffix). Default would
57 # be 'foo_bundle' otherwise.
58 bundle_name = "FooBundle"
59
60 # Signing your bundle is required to upload it to the Play Store
61 # but since signing is very slow, avoid doing it for non official
62 # builds. Signing the bundle is not required for local testing.
63 sign_bundle = is_official_build
64
65 # Enable language-based splits for this bundle. Which means that
66 # resources and assets specific to a given language will be placed
67 # into their own split APK in the final .apks archive.
68 enable_language_splits = true
69
70 # Proguard settings must be passed at the bundle, not module, target.
71 proguard_enabled = !is_java_debug
72 }
73```
74
75When generating the `foo_bundle` target with Ninja, you will end up with
76the following:
77
78 - The bundle file under `out/Release/apks/FooBundle.aab`
79
80 - A helper script called `out/Release/bin/foo_bundle`, which can be used
81 to install / launch / uninstall the bundle on local devices.
82
83 This works like an APK wrapper script (e.g. `foo_apk`). Use `--help`
84 to see all possible commands supported by the script.
85
86If you need more modules besides the base one, you will need to list all the
87extra ones using the extra_modules variable which takes a list of GN scopes,
88as in:
89
90```gn
91
92 android_app_bundle_module("foo_base_module") {
93 ...
94 }
95
96 android_app_bundle_module("foo_extra_module") {
97 ...
98 }
99
100 android_app_bundle("foo_bundle") {
101 base_module_target = ":foo_base_module"
102
103 extra_modules = [
104 { # NOTE: Scopes require one field per line, and no comma separators.
105 name = "my_module"
106 module_target = ":foo_extra_module"
107 }
108 ]
109
110 ...
111 }
112```
113
114Note that each extra module is identified by a unique name, which cannot
115be '`base`'.
116
117
118# Bundle signature issues
119
120Signing an app bundle is not necessary, unless you want to upload it to the
121Play Store. Since this process is very slow (it uses `jarsigner` instead of
122the much faster `apkbuilder`), you can control it with the `sign_bundle`
123variable, as described in the example above.
124
125The `.apks` archive however always contains signed split APKs. The keystore
126path/password/alias being used are the default ones, unless you use custom
127values when declaring the bundle itself, as in:
128
129```gn
130 android_app_bundle("foo_bundle") {
131 ...
132 keystore_path = "//path/to/keystore"
133 keystore_password = "K3y$t0Re-Pa$$w0rd"
134 keystore_name = "my-signing-key-name"
135 }
136```
137
138These values are not stored in the bundle itself, but in the wrapper script,
139which will use them to generate the `.apks` archive for you. This allows you
140to properly install updates on top of existing applications on any device.
141
142
143# Proguard and bundles
144
145When using an app bundle that is made of several modules, it is crucial to
146ensure that proguard, if enabled:
147
148- Keeps the obfuscated class names used by each module consistent.
149- Does not remove classes that are not used in one module, but referenced
150 by others.
151
152To achieve this, a special scheme called *synchronized proguarding* is
153performed, which consists of the following steps:
154
155- The list of unoptimized .jar files from all modules are sent to a single
156 proguard command. This generates a new temporary optimized *group* .jar file.
157
158- Each module extracts the optimized class files from the optimized *group*
159 .jar file, to generate its own, module-specific, optimized .jar.
160
161- Each module-specific optimized .jar is then sent to dex generation.
162
163This synchronized proguarding step is added by the `android_app_bundle()` GN
164template. In practice this means the following:
165
166 - If `proguard_enabled` and `proguard_jar_path` must be passed to
167 `android_app_bundle` targets, but not to `android_app_bundle_module` ones.
168
169 - `proguard_configs` can be still passed to individual modules, just
170 like regular APKs. All proguard configs will be merged during the
171 synchronized proguard step.
172
173
174# Manual generation and installation of .apks archives
175
176Note that the `foo_bundle` script knows how to generate the .apks archive
177from the bundle file, and install it to local devices for you. For example,
178to install and launch a bundle, use:
179
180```sh
181 out/Release/bin/foo_bundle run
182```
183
184If you want to manually look or use the `.apks` archive, use the following
185command to generate it:
186
187```sh
188 out/Release/bin/foo_bundle build-bundle-apks \
189 --output-apks=/tmp/BundleFoo.apks
190```
191
192All split APKs within the archive will be properly signed. And you will be
193able to look at its content (with `unzip -l`), or install it manually with:
194
195```sh
196 build/android/gyp/bundletool.py install-apks \
197 --apks=/tmp/BundleFoo.apks \
198 --adb=$(which adb)
199```
Matthew Cary39e62282019-03-07 14:56:08200
201The task of examining the manifest is simplified by running the following,
202which dumps the application manifest as XML to stdout:
203
204```sh
205 build/android/gyp/bundletool.py dump-manifest
206```