Posted by Maru Ahues Bouza, Developer Relations Partner, Google Play
Android Instant Apps provides rich, native experiences at the tap of a web link.
People can experience your app without upfront installation, enabling a higher
level and quality of engagement.
However, to provide comparable latency of loading a mobile webpage, an instant
app needs to be lean and well structured, so it can be downloaded and run
quickly in response to a URL tap. In light of that, we encourage that the binary
loaded in response any entry-point URL is as small as possible, with a maximum
of 4MB. The smaller the binaries, the faster the instant app will load and the
smoother the user experience.
This document will propose best practices for managing the application structure
and binary size to enable a smooth instant app experience. These practices will
also benefit your installable app.
Refactoring your codebase
The biggest binary size benefit comes from refactoring your app into
multiple
feature modules. Even if your current size and feature set don't require
multiple features, we recommend designing for it, so you can quickly add more
features in the future without affecting the binary size of existing features.
We also highly recommend having a unified modular codebase to produce both
installable and instant application binaries, as this will reduce the burden of
maintaining separate projects and code and provide a cleaner project structure
across both. Based on the experience of our early access partners, we believe
this will have the largest impact to the binary size at download. However, it
also requires the most investment.
To get to that end, you can start with a single (base) module and then refactor
code by moving relevant portions to feature module(s). Note that you do not need
to worry about the binary size while developing your instant app, as the size
limit does not apply for locally built binaries. You can also publish your
binary through the Play Developers Console to the
Development
track (special track for quick deployment of your instant app during
development), where the size limit is 10MB. [
1,
2]
The 4MB restriction is applied once your binary graduate out of the Development
track.
Each feature module can have one (or more) entry points – activities – that
correspond to a given URL. When splitting a single code base into multiple
modules, you will have different entry points for different features, and the
platform will load the relevant feature as needed. Remember, the total binary to
be downloaded for any given entry point should be under 4MB, so the combined
size of any feature module and the base module must be below 4MB.
It is advised to define the feature–activity–entry point mappings first, and
then structure the refactoring effort towards reducing the binary size for each
entrypoint..
Also consider how your libraries are included. If a specific feature module
requires certain libraries they should be included in the feature module only,
instead of being added in the base APK. This will reduce the size of the base
module. For example, let's say you have an application that depends on libraries
X, Y, and Z. Initially, you may pack all the libraries in the base module by
placing all the dependencies in the base gradle.build file. But if only the code
in the feature module requires library Z, it makes sense to move that dependency
from the base module to the feature module.This works as long as no other
feature modules depend on the same library. If multiple feature modules use the
same library it definitely makes sense to keep it in the base module.
Lint checks
Many apps tend to acquire a lot of resources, and over a period of time, some of
them are no longer used. Android Studio has useful built in lint check for
unused resources. Press Alt+Ctrl+Shift+I (Cmd+Alt+Shift+I on Mac OS), type
"unused resources" and start "Unused resources Android|Lint|Performance"
inspection. It helps to reduce the size of the installable APK as well.
String resources
Similar to resources, pay attention to strings, not all of them may be in use,
and typically the application size can be reduced significantly by removing
unused string resources. If application supports multiple languages, you may
want to reduce the number of localized resources, as it typically removes large
chunks of the resources assets. This is especially important if the app supports
only a few languages but uses AppCompat library, which includes messages in
multiple languages. Use
resConfig
to select specific resources configurations only. Hint: typically you can use
"
auto"
to restrict configurations pulled from third-party libraries to match the set of
configurations defined in your project.
Switch to WebP
Significant reduction of the
drawable
resources size may be achieved by switching to
WebP
images instead of PNGs. Android Instant Apps supports all features of the
WebP format (transparency, lossless, etc.) so there will be no loss in
functionality. Keep in mind that application launcher icons must use PNG format,
but it should not be a problem since projects normally keep those in mipmap-
directories. If a backward compatible solution is required, you need to include
the original PNG images in the APK module and it will
override
WebP resources automatically (main source set overrides all resources from
AAR/feature module). [
4]
Of course, going with vector drawables may let you save even more of the
precious space, but using vector drawables will require a code change while the
above mentioned trick with WebP images for the instant app and PNG images for
the installable APK requires no code modifications.
Download assets at runtime
Finally, remember that technically there is no need to pack all the resources in
the instant app APKs, as the application can download additional assets at run
time. This approach also enables the app to download the required assets only.
These modifications may require significant changes to the code base, but will
also help you to reduce the size of the installable APK.
If shrinking resources does not bring your app feature modules size under the
limit, it is time to look for the ways to reduce the code size.
Review native libraries
Some third-party libraries may include native code, which may not be used in the
instant app at all. So the first step is to review the native libraries packaged
within the APK and make sure the instant app has only those that are actually
used. Remember to look into the compiled APK using
APK
Analyzer (Build -> APK Analyzer…) [
5]
Review external libraries
Next review the list of all external libraries linked with the app's code. You
may find some unexpected surprises courtesy of transitive dependencies.
Transitive dependencies occur when the library your project relies upon depends
on another library, which in turn may depend on yet another library. Sometimes
those transitive dependencies may contain unexpected surprises such as libraries
you do not need at all (i.e. a JSON processing library you never use in your
code.) Please see "
Excluding
transitive dependencies" section in the Gradle User Guide for further
details.
Android Studio has several useful tools for analyzing the external dependencies
for the project. It always helps to start with the Project view:
The "Project" view shows a section called "External libraries", where you can
see all the libraries used by the project including any transitive dependencies:
In order to further reduce the base feature size you may need to pay attention
to the code dependencies and external libraries. Check the "Project" view and
look for unused libraries that might be transitive dependencies the project does
not need. Also look for libraries that provide the same functionality (e.g.
multiple libraries for image loading/caching). [
4]
You can also compare different builds with
APK
Analyzer tool, and it works with instant APKs, too.
Finally, review the list of transitive dependencies and exclude the ones you do
not need. Use the following command to review the dependencies graph:
gradle -q :MODULE:dependencies --configuration compile
. Further
details can be found in the
Gradle
documentation.
Other tips
Android Studio 3.0 includes the App Links Assistant tool, which can help to
generate the necessary intent filters, and help in splitting the project into
several modules. [
3]
Once you got the instant app bundles under the size limit, it is the time to
make sure the building process is up to date. Check that the application package
and instant app APKs are signed using the "
APK
Signature Scheme v2". If you sign the APKs using the latest version of the
SDK tools, everything should be done automatically. However, if you manually
sign the build artifacts you need to avoid using jarsigner and switch to
apksigner
instead.
And a few useful tips for adapting the app's code to the instant runtime
environment. Keep in mind that having a small branches of code for
instant/installable applications, based on the
InstantApps.isInstantApp(...),
should be fine and typically does not make the source code unreadable (unless
you abuse it, of course). Also, when using share intents make sure the code does
not explicitly enumerate applications installed on the device, instant app
security model does not allow that. Simply use regular Intent.createChooser() to
present the list of all possible actions to the user.
The level of effort of developing an instant app for an existing Android
application varies across developers and is heavily dependent on how your
application is organized today. For some, it will be easy as your project is
already organized as multiple modules. However, for some, the focus will be on
reducing the code and resource assets size, and we have introduced tools and
Android platform features above to help you with that.
Hear from other developers using Android Instant Apps
Finally, check out these great posts by developers that have already built an
instant app:
Visit the Android Developers website to
get
started with Android Instant Apps and
check out more
instant apps success stories from other developers.