Grab shrank its superapp by a quarter in order to survive

Large APKs and disk footprints spell doom in a developing market

In 2019, Southeast Asian superapp developer Grab spotted a problem: its app was growing in size by one percent per month, making it less suited to the modest smartphones found across the region in which it operates, degrading user experience and ultimately threatening its prospects for attracting more users.

"As the app continues to expand with more features, Grab identified the need for a consistent, high-quality experience for new users who may have limited storage space or restricted internet bandwidth," explained the developer on its engineering blog last week.

The Grab app started out providing ride-hailing, and expanded over the next decade into food delivery, parcel delivery, mobile payment, and even its own driver-targeted loans.

Not every user utilizes every offering, yet all features remain present in the app – which grew to four million lines of code.

In Q3 2021 the Singapore-based outfit therefore initiated Project Bonsai – an effort to reduce its app's download size and disk footprint. Over six months it improved the former by 26 percent and made an unspecified dent in storage requirements too.

Prior to Project Bonsai, Grab was already using an app bundle approach and tailoring APKs to specific device configurations. Additionally, it monitored changes to the app, established debug build (APK file size) monitoring for every commit merged to the master branch, employed R8/Proguard as a "code shrinker," made use of vector images when possible instead of raster images, enabled resourceConfig to rid itself of languages not used in its regions, and reviewed third-party libraries for bloating.

But all this was not enough. So with Project Bonsai, Grab looked to measure, reduce and contain the size of its app by whatever means necessary.

It started by building a custom tool to analyze binaries from bundle files. It named the tool App Sizer and integrated with its workflow.

The tool sends data to a Grafana instance for monitoring and observability of device-specific app download size, identifies which libraries and modules use the most storage space, and creates a list of large files.

Grab plans to open source the tool in the near future.

To reduce the app's size, Grab decided not to add anything new, but target the biggest offenders it could find.

"Our concentration centered on optimizing the dex file size, refining resources, and eliminating duplication and redundancy," explained Grab.

Java/Kotlin code was the major contributor of app size, and thus became a top priority for optimization. And within that code, R classes were the major culprit. "R classes contained ID references not only to their own resources but also to resources from their transitive dependencies," noted the blog authors.

"This meant that if Module A depended on Module B, and Module B in turn, depended on Module C (Module A -> Module B -> Module C), then Module A's R class included ID references to resources from Modules B and C, even if Module A didn't directly utilize these resources. This explained why R classes in a modularized project could accumulate millions of lines of code," the authors explained.

The superapp shop also found that its app contained over 1,500 modules and third-party libraries, which led to the generation of significantly large R classes. This did, however, explain why software engineers saw spikes during certain commits, despite no significant additions of resources, libraries, or code.

"These fluctuations were linked to changes in the dependency graph, further emphasizing the impact of Transitive R classes," Grab's devs recalled. Furthermore, R classes were being preserved thanks to default rules. This was fixed by updating the AGP version after performing an automation test to avoid inadvertently removing used R class fields. This test was done by script to search for instances where R class reflections were used. Third-party libraries were decompiled and applied the same script. Next, Grab revised its R8 configuration rules looking for redundancy.

Bin the bloat

When large files were found, the responsible team was encouraged to remove them if deemed unnecessary, consider offloading to a cloud server, or converting them to more economical file formats.

Even fonts were streamlined as the superapp removed rarely used typefaces and eliminated duplicates. Grab is now working to adopt a single font.

"Our recommendation is to explore the use of one primary font style, with the flexibility to incorporate different typeface variations in your programming to achieve various typefaces using the same font," Grab's post explains.

One specific library was found to account for eight percent of the app's storage footprint. Grab removed it, and worked to remove duplicate functions across other libraries.

An addition to the app – a toggle to disable a feature remotely – also helped the reduction effort.

"It's very useful for running an experiment or turning off if a feature causes us any problems," noted the blog authors.

Grab continues to find explore methods to keep its app trim – including common UI design components and experimenting with dynamic delivery.

Grab is considering allocating each team a mandatory "app size budget."

"By prioritizing code optimization, resource management, modularization, and asset bundling, we achieved substantial optimizations in app size while enhancing user experience," boasted Grab.

The problem of app bloat is one that is not likely to go away – particularly in Southeast Asia as smartphone use continues to grow, but consumers' ability to pay for them doesn't.

Last year a YouGov survey of Asian consumers found three quarters of respondents between age 18 and 40 prefer mid-range phones due to their keen prices, even though that means missing out on some features. The study was sponsored by Xiaomi-backed brand Poco – so maybe take it with a grain of salt. ®

More about

TIP US OFF

Send us news


Other stories you might like