App Diets are not a Fad

(This is our second guest post by Mikhail Nakhimovich. By day Mikhail Nakhimovich is an architect of the award winning New York Times Android App and by night he writes about Android and helps startups create performant, delightful apps with his team at Friendly Robot .)

In our last post we explored an architecture/library selection that would lead to near perfect startup times. Today I wanted to explore another type of performance optimization: APK size. A smaller APK leads to faster resource lookup and faster reflection. Image optimizations, an important way to cut down APK size, lead to fewer dropped frames. Users overall love apps that take up minimal space and data to download.

I was fortunate enough to attend Google’s I/O this year where Wojtek Walicinski gave a great talk on how to reduce APK size (“Putting Your App on a Diet”). I’d recommend that you watch the full video , but this article will summarize the main points. We’ll also dive deeper on the main concepts in a Q&A with Boris Farber, a Google Developer Advocate and expert on performance.

Why (App) Size Matters

In a word? Performance. Apps are faster when they have fewer resources to load. I’ve seen 30% speed improvements for layout inflation after removing 20k methods from my app.

Plus, it’s worth remembering that while many users in the U.S. are not constrained by data limits, this isn’t true throughout much of the world. It’s common in many countries for users to pay per megabyte, which makes reducing APK size a central part of offering a positive user experience.

How to Think about App Size

What do we mean when we talk about the size of our app? There are several different measurement categories:

  • Raw APK Size . This is interestingly the most talked about metric but least relevant for your users.
  • Download size . How many megabytes needed to download.
  • Install size . This refers to how much space it actually takes up on the device.
  • Update size . Size of the update.

APK Size

When thinking about APK size, it’s worth remembering that an APK is just a zip file. An Android APK contains several parts: + Byte code . This includes classes.dex (your app’s sources) as well as any libraries and library binaries that you’ve imported. These can be Java or Android + Native code . C-libraries for architecture (.so files) + Resources . This is basically everything else: strings, colors, images, the Android Manifest, and the META-INF folder. NimbleDroid actually does a great job of showing you size of the various parts of your APK on upload. Check out Facebook’s APK file profile .

Download Size

Sometimes developers see how much data it takes to download their APK and try to figure out how they can reduce it. One might see that Resources.arsc can get pretty big, think that strings are compressible and compress it. This is actually a bad idea because once the APKs is downloaded, the framework needs to uncompress and hold the entirety of the uncompressed resources in memory to read a single string. As a result, compressing your resources is actually an anti-pattern. If you’re wondering how resource loading normally works, the framework memory maps the file when it is not compressed and optimizes how it stores/accesses strings directly from specific memory address. Additionally, the Play Store serves a compressed version of your APK to keep bandwidth down. It’s important to know exactly what is happening to an APK prior to trying to shrink it.

Install Size

An APK contains files that include architectures and different device size resources. Unfortunately, there’s nothing your phone can do to strip these out after installation. Only on Lollipop and Marshmallow devices, ART would take your raw APK and compress it to a OAT native file. N will be going back to using a JIT compiler. This means no more optimizing apps on install.

Update Size

When a user wants to download an update, the delta or missing classes/resources are computed. Next, the Delta classes/resources are compressed. The device downloads difference and reconstructs the APK on device. The algorithms that Google is using for diffing are constantly changing/improving (current is BSDiff). Play Store will now show download size rather than APK size. On update users will see the update size.

There were packaging improvements in Studio 2.2 that also help reduce APK size: + Sort all files in archive by name + Zero all timestamps + Zero empty space in archive + Ability to store uncompressed *.so files

You might be wondering how optimizations affect APK size. Google has recently open sourced APK Patch Size Estimator created by Julian Toledo. This shows estimates for new API size on disk, new API Gzipped size (download size for new installs), Gzipped BsDiff Patch Size (size of updates).

Here are some recipes for how to keep your APK size to a minimum:

First is an anti-pattern: the Zopfli compression of APK. Zopfli was developed at Google as an alternative compression. The good news is that it makes your APK smaller. The bad news is that it has extreme resource consumption during compression and may not work with new compression algorithms for differential updates. As a result, it is recommended to not Zopfli-compress a whole APK anymore.

Shrinking your Images

So now for the good stuff. We’ll start with image compression. You’ll need to use an external tool to preprocess images. If you are using an external tool to compress your images, you’ll need to disable the default compression during the build phase. You can do this by adding the following to your build.gradle file to prevent build tools from processing the images and making them bigger.

 aaptOptions {     cruncherEnabled=false } 

Interestingly enough you can Zopfli pngs. They will look the same (lossless) and be just as fast.

If compression isn’t your thing, you can also switch to WebP. It is 30% smaller than Jpeg, works on Android 4.0+ for non transparent PNGs, and works with transparency and lossless images in 4.2.1+.

As far as Android specific formats, Vector Drawables are amazing for icons. This is a text based format that now has a support library to boot. Another text based drawable format is ShapeDrawables, which has support dating back to Android 1.0. Shape Drawables are great for button backgrounds, borders and gradients.

Shrinking your Code

The best way to shrink code is to use Proguard. You will hate Proguard but will love being under the dex limit. Proguard will strip all methods without an execution path out of your APK. Turning on Proguard is trivial. All you have to do is add minifyEnabled true to build.gradle. The tricky part is maintaining a list of rules that specify which classes to keep. These rules are kept in the aapt_rules.txt file. This is where the Android specific files are stored. You can also specify that a method should be retained by adding @Keep to a method to flag it for keeping by Proguard. You just need to make sure to keep anything that might be called through reflection.

Besides using tools like Proguard, one can also do investigation into exactly what is going into their apk. More often than not a big dependencies can be pulling in quite a few methods/resources. The first thing you can do to analyze dependencies is run a gradle task: ./gradlew app:dependencies. This will lets you see tree of all your dependencies. Alternatively, you can use the excellent open source tool ClassyShark github.com/google/android-classyshark. Classyshark is an APK file explorer that’s great for debugging Proguard. (See bonus interview with the author at end of article)

Shrink Your Resources

Another tactic for cutting app size is shrinking resources such as Strings or styles you forgot to remove. If you’re using Proguard, you can add shrinks.Resources true to build.gradle to remove any unused resources in your app.

Advanced App Shrinking

The final strategy for cutting APK size is to segment your app into parts based on density, texture (game development), or architecture, so users can download only the code and resources tailored to their device. You can do this by splitting the APK into many smaller APKs targeted at devices and upload them all to the Play store.The only caveat is that you will need to generate different version codes for each APK. Otherwise, splitting APKs is trivial:

 android {     splits {         density {             enable true             exclude ldpi, tvdpi, xxxhdpi             compatibleScreens small, normal, large', xlarge         }         abi {             enable true             reset()             include x86, armeabi-v7a             universalApk true         }     } }  

Hear from an Expert – More on Classy Shark

For a deeper dive into app slimming tactics, I got the skinny from Boris Farber , a Google Developer Advocate and the author of Classy Shark.

Q. When an app is slow, what is first thing you look at?

I always start by looking at the dependencies. Usually, the problem is not that my code is slow, especially on new devices. The problem is more often that I am using different things that I do not know the cost off. Don’t worry too much about optimize your code, optimize your decisions. [Note: NimbleDroid shows you problematic dependencies]

Q. Classy Shark was mentioned in Wojtek Walicinski’s I/O talk about APK size. Could you give a little detail on what it is?

Classy Shark is a browser that allows me to look at APK as a first class citizen. Now something that runs on your user device is something that you can think and reason about. Rather than sharing shell scripts you share something within a tool.

Q. What are some of the use cases that merit considering Classy Shark?

I’d say you should use it as a toothbrush–twice a day. Always keep your finger on what is going on in the APK. If you add a dependency, check Classy Shark. The earlier you find problems the better. If you find them later in the process, it makes change more painful.

Q. I’ve worked on projects where the libraries we used were not perfect for the use case which hurt performance. What do you look for when evaluating whether to add a new library to your app?

When I consider a library, the most important criteria is, “does this library solve my problem?” I try to find three to four candidate and then do evaluation. This includes looking at the dex count, how it plays with other dependencies I am using, and evaluating performance in the app, but the most important thing is that it has to solve my problem.

Q. Do you have advice for developers who work in an organization that doesn’t prioritize performance?

Well, we’ve found that Play store reviews are correlated highly with APK size and performance. Things should not be taking to far to other end, don’t prematurely optimize. Find specific bottlenecks/problems and then figure out if it is worth optimizing. Some companies optimize throughput, others need graphic processing. Your solution needs to fit the specific problem and so does your proposal.

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » App Diets are not a Fad

分享到:更多 ()

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址