Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to Android App Bundle format for Play Store uploads #3547

Closed
gnprice opened this issue Jul 8, 2019 · 3 comments
Closed

Switch to Android App Bundle format for Play Store uploads #3547

gnprice opened this issue Jul 8, 2019 · 3 comments

Comments

@gnprice
Copy link
Member

gnprice commented Jul 8, 2019

This would be nice to do because it would probably make our app somewhat smaller to download. Major apps with lots of developers reportedly get 10-40% smaller. Our recent releases are about 11MB as APKs.

Also, I get a reminder about this every time I upload a new release to the Play Store, or promote a release to beta or production.

Some information here (including the figures I've summarized as "10-40%"), and links to more info:
https://developer.android.com/platform/technology/app-bundle

Relevant in particular for us:
https://developer.android.com/studio/build/building-cmdline#bundle_build_gradle

gnprice added a commit that referenced this issue Jul 26, 2019
This fixes #3323, meeting the Google Play 64-bit requirement that
comes into effect next week, 2019-08-01 -- in other words, it makes it
possible for us to continue uploading new releases after that date.

Aside from ticking a box, it's expected to improve performance on
devices with 64-bit CPUs -- which is most new devices of the last few
years, and 85% of all our installs on active devices as reported by
the Play Console.  (In "Release management > Device catalog",
filtering "ABI" to `arm64-v8a` or `x86_64`.)

The main work to make this possible happened in RN upstream; we pulled
it in with our upgrade to RN v0.59, #3399.  This is one last fragment
of the diff in upstream's template app between those versions,
enabling 64-bit versions in our build config.

One unfortunate regression this causes: we're still distributing a
single APK for all architectures, and so adding 64-bit architectures
makes it a lot bigger.  At a quick estimate from comparing
`yarn build:android-nokeys` before and after, we go from 13MB to 22MB.

The Play Store has had a solution to that for a while now, called
"Android App Bundle".  We should switch to that.  We're already
tracking that task as #3547, and this change increases its priority.
@gnprice
Copy link
Member Author

gnprice commented Jul 26, 2019

Bumping up to P1, because adding 64-bit libraries (#3323) just now increased our APK size by quite a lot, and this will reverse that increase. A release build from yarn build:android-nokeys was 13.0MB just before that change (the increase from the 11MB I quoted above is perhaps from the RN v0.59 upgrade, #3399), and is 21.8MB after.

In fact, it should more than reverse it -- from inspecting the APK while working on #3323 , I just noticed that we're shipping not two, but four versions of all the native code. Here's a list of the biggest files within the APK, one that compresses to 21.8MB:

$ unzip -l android/app/build/outputs/apk/release/app-release.apk | sort -rn | head
 61028605                     858 files
  9599984  1980-00-00 00:00   lib/x86_64/libjsc.so
  8809472  1980-00-00 00:00   lib/arm64-v8a/libjsc.so
  7836488  1980-00-00 00:00   lib/x86/libjsc.so
  7054492  1980-00-00 00:00   classes.dex
  6901812  1980-00-00 00:00   lib/armeabi-v7a/libjsc.so
  3848596  1980-00-00 00:00   assets/index.android.bundle
  1120816  1980-00-00 00:00   lib/x86_64/libc++_shared.so
  1095476  1980-00-00 00:00   lib/x86/libc++_shared.so
  1055016  1980-00-00 00:00   lib/arm64-v8a/libc++_shared.so

The quoted sizes are uncompressed. Note the four different versions of libjsc.so, the JavaScript implementation. Note that in addition to two ARM architectures, we have them for x86 and x86_64... architectures which, much to Intel's chagrin, are all but nonexistent on mobile devices. (The Play Console -- this info is at "Release management > Device catalog", as a breadcrumb for my future self -- says they account for about 0.9% of our installs on active devices.) But all those ARM phones are downloading x86 versions of that and RN's other native libraries, on every update to our app, since forever.

At a rough estimate, if the app is still about 22MB before we take care of this, this means it should get reduced to 9-10MB -- well under half the size.

@rk-for-zulip
Copy link
Contributor

This should be relatively easy to accomplish: we simply need to run :app:bundleRelease rather than :app:assembleRelease at release time, and upload the produced .aab file to Google Play.

I'm not sure about Sentry yet; they do appear to have some support for AABs, although we may need to upgrade. (But then, I half expect that'll be needed for #3585 as well.)

@gnprice
Copy link
Member Author

gnprice commented Oct 15, 2020

I've made some changes in our release scripts to support AABs, and in our release-process documentation to make them the primary form for the release. I've run through that process for the upcoming v27.156, up to alpha stage, and everything seems to work. (Chat thread starts here.) So, closing this issue as done.

The resulting download-size savings seem to be in line with what we hoped. Our APKs have grown since the above comments (at least partly from RN upgrades; some investigation in chat), to 30.0 MB for v27.156. But the download size is estimated by the Play Console at 12.4 to 13.4 MB, and when I tried the download for my own main device it was 13.8 MB. That's a savings of a little over 16 MB or 54%, which makes it a little more in absolute terms and a little less in relative terms than we estimated earlier.

@gnprice gnprice closed this as completed Oct 15, 2020
gnprice added a commit that referenced this issue Oct 16, 2020
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this issue Oct 22, 2020
We don't want to be using JavaScriptCore forever, if we can avoid
it; we're tracking the switch to Hermes as zulip#4131. In fact, Hermes
doesn't yet support Intl.

For now, this tiny code change will allow `react-intl` to work on
Android. A `react-intl` doc [1] links to instructions [2] [3] to use
a variant of JavaScriptCore that supports `Intl`. So, follow those
instructions.

Reportedly, this change will add 6MiB per architecture. zulip#3547 was
recently resolved, though, giving us some wiggle room.

[1] https://formatjs.io/docs/react-intl/#react-native
[2] https://github.com/react-native-community/jsc-android-buildscripts#international-variant
[3] They're slightly out-of-date, currently, but it's still easy to
    tell what to do; see
    facebook/react-native@d7f5153cd#diff-b8dd15c78827c1b48f9fe21c45686142R100-R111
    for the new edit to make to `android/app/build.gradle`.
chrisbobbe added a commit to chrisbobbe/zulip-mobile that referenced this issue Oct 22, 2020
We don't want to be using JavaScriptCore forever, if we can avoid
it; we're tracking the switch to Hermes as zulip#4131. In fact, Hermes
doesn't yet support Intl.

For now, this tiny code change will allow `react-intl` to work on
Android. A `react-intl` doc [1] links to instructions [2] [3] to use
a variant of JavaScriptCore that supports `Intl`. So, follow those
instructions.

Reportedly, this change will add 6MiB per architecture. zulip#3547 was
recently resolved, though, giving us some wiggle room.

[1] https://formatjs.io/docs/react-intl/#react-native
[2] https://github.com/react-native-community/jsc-android-buildscripts#international-variant
[3] They're slightly out-of-date, currently, but it's still easy to
    tell what to do; see
    facebook/react-native@d7f5153cd#diff-b8dd15c78827c1b48f9fe21c45686142R100-R111
    for the new edit to make to `android/app/build.gradle`.
gnprice pushed a commit to chrisbobbe/zulip-mobile that referenced this issue Oct 23, 2020
We don't want to be using JavaScriptCore forever, if we can avoid
it; we're tracking the switch to Hermes as zulip#4131. In fact, Hermes
doesn't yet support Intl.

For now, this tiny code change will allow `react-intl` to work on
Android. A `react-intl` doc [1] links to instructions [2] [3] to use
a variant of JavaScriptCore that supports `Intl`. So, follow those
instructions.

Reportedly, this change will add 6MiB per architecture. zulip#3547 was
recently resolved, though, giving us some wiggle room.

[1] https://formatjs.io/docs/react-intl/#react-native
[2] https://github.com/react-native-community/jsc-android-buildscripts#international-variant
[3] They're slightly out-of-date, currently, but it's still easy to
    tell what to do; see
    facebook/react-native@d7f5153cd#diff-b8dd15c78827c1b48f9fe21c45686142R100-R111
    for the new edit to make to `android/app/build.gradle`.
gnprice added a commit to gnprice/zulip-mobile that referenced this issue Mar 14, 2022
This bit of code doesn't currently do anything, because we build a
single APK for all devices.  It would if we started building split
APKs per ABI.

This sort of thing was required for publishing an app as multiple APKs
on Google Play.  (The docs link in the comment is broken; a current
version appears to be:
  https://developer.android.com/google/play/publishing/multiple-apks#VersionCodes
.)  Google Play would use the different version codes as tiebreakers
to decide which APK to give to a device when several were supported.

But on Google Play, publishing multiple APKs has been obsolete for
years.  Instead, one uploads a single AAB, "Android App Bundle", and
then Google slices and dices that into separate APKs for the per-ABI
files, the per-screen-density files, the per-screen-size files, and
so on.  Each device downloads the specific combination of those pieces
that applies to it.

We never did publish multiple APKs on Google Play, and because it's
now obsolete we never will; we've been using AABs since zulip#3547 in 2020.

We do intend to start publishing multiple APKs, which would cause this
bit of code to start having an effect.  But this convention doesn't
seem to be useful anywhere else: for a user installing directly from
our GitHub release it's invisible and unhelpful, and the one known
downstream distributor of our APKs plans to just distribute the one
most widely-supported of them anyway:
  zulip#1270 (comment)
which will make this hack have no use there either.

So it seems like messing with the version codes like this would only
cause confusion.  Instead, just let the different per-ABI APKs for a
given release have the same version code as each other, and as the AAB
does.  That way the next release after v27.181 will have version code
simply 182, rather than 182003 et al.
gnprice added a commit to gnprice/zulip-mobile that referenced this issue Mar 14, 2022
The great bulk of the size of our APK comes from the native
libraries in it (most of all libjsc.so).  Those exist in a
separate copy for each of our 4 ABIs, but any given device
is going to use only one of those.

So, build a separate APK for each ABI.  The new APK for arm64
(the most common) is 40.3MB, compared to 132.3MB for the old
all-in-one APK.

This has no effect for the many Android users who get our app via
the Google Play Store: there, we already upload an AAB, which
Google splits up into several APKs still more finely.  See zulip#3547.

Fixes: zulip#5295
gnprice added a commit to gnprice/zulip-mobile that referenced this issue Mar 14, 2022
The great bulk of the size of our APK comes from the native
libraries in it (most of all libjsc.so).  Those exist in a
separate copy for each of our 4 ABIs, but any given device
is going to use only one of those.

So, build a separate APK for each ABI.  The new APK for armeabi-v7a
(the most widely-supported) is 35.1MB, compared to 132.3MB for the
old all-in-one APK.

This has no effect for the many Android users who get our app via
the Google Play Store: there, we already upload an AAB, which
Google splits up into several APKs still more finely.  See zulip#3547.

Fixes: zulip#5295
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants