24

I am not sure, if I got this right. It seems it is doing the oposite. If I keep the flag android:extractNativeLibs set to true, the app is taking about 70MB of user's space (yeah...) but if I set this flag to false, the size of the app installed on the device jumps to about 95MB. So I am not sure if user would appreciate this.

egoldx
  • 1,490
  • 1
  • 9
  • 14
  • What is your problem?I'm not getting. –  Mar 24 '17 at 11:30
  • 2
    This is actually correct, it will reduce the run time memory of the app as it will not copy the so file into system. .so file will be directly loaded from apk. Also, check if u can disable the debug symbols as mentioned here. https://developer.android.com/topic/performance/reduce-apk-size.html#reduce-code – siva Mar 24 '17 at 11:32
  • Thanks, I will try that. – egoldx Mar 24 '17 at 12:23

3 Answers3

63

This is a bit tricky. Your APK size is going to be larger when extractNativeLibs is set to false.

Old behavior

When extractNativeLibs is set to true (default) or not added to the manifest, your native libraries can be stored compressed in the APK. They are extracted by the PackageManager during installation, and a copy is put to /data/app/. As a result, there are two copies of the native library - a compressed in the APK, and an uncompressed in /data/app/.

This approach has the following advantages:

  • smaller APK size because the libraries are compressed

Drawbacks:

  • increased installation size ("storage" or "on disk" in Settings=>Apps) because in addition to the APK, the extracted native libraries are taking space on disk
  • longer installation times
  • less optimizations from Google Play, for example when generating update patches

New behavior

New approach introduced by Google in Marshmallow (Android 6) is enabled by setting extractNativeLibs to "false". It expects the libraries stored uncompressed in the APK (STORE method) and zipaligned. There's no need to extract them during installation. On app startup, the libraries can be loaded (memmapped) directly from the APK.

Advantages:

  • decreased installation size ("storage" or "on disk" in Settings=>Apps) because there's no need to extract the libraries. Basically, the occupied space is usually just a bit more than the APK size
  • no increase in the download size from Google Play, because it uses its own compression on top of APK
  • optimized update patch generation by Google Play, resulting in smaller update sizes. If you update your native lib, the compressed version will have huge differences causing a larger patch, while a patch for an uncompressed library is going to be relatively small.

Disadvantages:

  • larger APK size because the native libs are not compressed

Expectedly, I didn't find a noticeable difference in loading performance of both options.

Conclusion

The extractNativeLibs="false" option could be useful for your if:

  • you don't care about the APK size - either it is well under 100 Mb limit or you are already using expansion files (OBB) and can handle the APK size increase
  • you care about the update size of your app in Google Play
  • your native libraries are not very large.

For example, for a game made with Unity, this option is hardly applicable because of the large native libraries.

UPDATE: Android App Bundles

Android App Bundles are a new distribution mechanism announced by Google Play, more details available on the official websites https://developer.android.com/platform/technology/app-bundle/ and https://developer.android.com/guide/app-bundle/

It has significant advantages over a traditional APK, one of the most important being the 150 Mb max size limit. Important: this is the download size, not the size of the app bundle itself or the generated APK. (APKs are generated by Play and delivered to the device on-the-fly, more details on how it works should be available on official Android resources).

When building an AAB, it has the extractNativeLibs flag set to "false" by default. However, as Google Play applies compression on top of the APKs delivered to the end device, this doesn't affect the download size. It means that this flag brings only benefits in case of Android App Bundles - faster installation, less size on disk at almost no additional cost because of no pressure towards the max size limit.

One confusing thing however is how to calculate the download size when you're close to the 150 Mb limit, because the AAB size is not an indication of the download size. There is a special command for that in the bundletool https://developer.android.com/studio/command-line/bundletool#measure_size, or you can try uploading it to Play directly. If your AAB is well under 150 Mb, there's no need to worry then.

(Update: using 150 Mb size limit instead of 500 Mb for app bundles; apparently 500 MB was available in developer preview but is not public as of now).

Over17
  • 961
  • 7
  • 8
  • 1
    Additional behavior: Install will fail with message "INSTALL_FAILED_INVALID_APK", and shows other symptoms which disturbs native debug (like breakpoints in native codes don't work), occasionally. – Toris Apr 26 '18 at 13:58
  • anything we have to take in proguard rules to keep it false – Anand Phadke Oct 17 '18 at 12:46
  • 1
    The bundle tool for Android App Bundles can provide apk download size estimation. See: https://developer.android.com/studio/command-line/bundletool#measure_size – Chris Li May 03 '19 at 06:16
  • @Toris, do you have idea why 'setting android:extractNativeLibs=false' could cause the behaviors you mentioned? Thanks~ – Chris Li May 03 '19 at 06:29
  • How can I make sure that the requirement for "extractNativeLibs=false" are met? Just add "zipAlignEnabled true" to the release in buildTypes? Does extractNativeLibs affect debug-mode APK too? – android developer Jan 02 '20 at 15:11
  • @androiddeveloper good question. I don't know for sure but I think if you don't zipalign, you will likely get a crash on start. At least when I was adding support for this option in Unity, I experienced quite some crashes before it worked. On debug APKs, I think it all works the same because this flag affects the way the APK is installed by the package manager, and the way native libs are loaded on start. – Over17 Jan 10 '20 at 09:07
  • 1
    @Over17 I think it matters only on signed apps. – android developer Jan 10 '20 at 20:19
  • You talk about "old" and "new" behavior, and refer to the new one as the one that came with Marshmallow. But I only see extractNativeLibs being available since Marshmallow. How can I use it on Lollipop and older? – Edw590 Apr 30 '21 at 16:47
  • 1
    @DADi590 well you can't. This is a feature in package manager (to not unpack the libraries) and the loader (to allow loading uncompressed libs directly from the APK). If it's not supported by the OS, you can't do much. You could potentially emulate loading directly from the APK, but the OS will still unpack the libs so doesn't make sense. – Over17 May 03 '21 at 08:08
  • I'm trying here that the libraries can't be touched (on M and above, seems I need to do nothing except putting `extractNativeLibs` false). If I'm loading from the APK itself, the OS can extract at its will, but it won't be used, and I don't need more work to check if the library is still available or if it was deleted (app for rooted phones, and to be installed as a system app - an assistant app). "You could potentially emulate loading directly from the APK" - would you know how? (if possible) – Edw590 May 03 '21 at 10:22
11

extractNativeLibs="false" could be counterproductive if your APK contains multiple ABIs. Let's say you're using a library which is 10 MB for each ABI and can be compressed to 5 MB. If you have 3 ABIs, then the result is:

extractNativeLibs="true":

APK:       15 MB (3 x 5 MB)
Extracted: 10 MB
Total:     25 MB

extractNativeLibs="false":

APK:       30 MB (3 x 10 MB)
Extracted:  0 MB
Total:     30 MB

As of 2019, the recommended way to mitigate this is to use the Android App Bundle format.

mario.van.zadel
  • 2,919
  • 14
  • 23
mhsmith
  • 6,675
  • 3
  • 41
  • 58
2

There are some important preconditions for that to work though and that’s where things get more complicated:

  • The .so files inside the APK cannot be compressed — they must be stored.
  • The .so files must be page aligned using zipalign -p 4

Update: The part below is only valid for Android Studio version 2.1 and lower. Starting from Android Studio 2.2 Preview 2 and newest build tools, the build process will automatically store native libraries uncompressed and page aligned in the APK.

Fore more information: link

Update: If at some point you sign your app manually, it matters when you invoke zipalign.

Caution: You must use zipalign at one of two specific points in the app-building process, depending on which app-signing tool you use:

  • If you use apksigner, zipalign must only be performed before the APK file has been signed. If you sign your APK using apksigner and make further changes to the APK, its signature is invalidated.
  • If you use jarsigner, zipalign must only be performed after the APK file has been signed.

Source: zipalign | Android Developers

Android 6+ will prevent you from installing a misaligned APK with uncompressed native libraries. Older Android doesn't care and always extracts native libraries.

Community
  • 1
  • 1
Mehatab
  • 1,689
  • 1
  • 11
  • 6
  • I get that, but the problem is, that I expected total size to be smaller with `android:extractNativeLibs=”false”` but its the oposite - it's about ~25MB larger. Tested on Android 7.1.1 – egoldx Mar 24 '17 at 12:28