You must specify an ABI for each CPU architecture you want your app to work with ... To build machine code for two or more distinct ABIs, using spaces as delimiters. For example:
APP_ABI := armeabi armeabi-v7a
This setting tells the NDK to build two versions of your machine code: one for each ABI listed on this line.Whereas the post says:
To reduce our APK size and ensure that our App would run on all possible devices, we have flavors of our App for the x86, Armv7 and Arm architectures. Each flavor only contains the native libraries corresponding to its respective architecture
There we have it.
When you build multiple machine-code versions, the build system copies the libraries to your application project path, and ultimately packages them into your APK, so creating a fat binary. A fat binary is larger than one containing only the machine code for a single system; the tradeoff is gaining wider compatibility, but at the expense of a larger APK.
Furthermore, Google play explicitly allows you to offer multiple APKs, each targeting a specific device configuration [0], although there they do "encourage you to develop and publish a single APK that supports as many device configurations as possible".
Having said all of this, none of it is relevent to the main problem discussed, which is that the installer failed to unpack the libraries.
[0]http://developer.android.com/google/play/publishing/multiple...
It's also worth noting that Chromium removed their workaround and are shipping a new native library loader purely to optimize for the fact that they are now the system WebView implementation, thus they need to reduce RAM usage when they are loaded by many running processes.
https://chromium.googlesource.com/chromium/src/base/+/master...
As to why the installer failed to unpack the libraries, it's a bit suspicious that the article doesn't mention an investigation of the root cause nor called it a bug on Google's end. My hunch is that the root cause is somewhere in between making some un-documented moves in Android.mk and how the package generator picks up the libraries.
Trust me, we've read the documentation surrounding this multiple times.
So: First, ensure that your app runs for everyone. Then find ways to reduce the APK size without compromising that.
And yes, I'm aware that Android / Google Play has added APK splitting, allowing platform-specific APKs to be distributed from the Play store. I actually would argue on balance this was probably a bad idea which presumes an iTunes-like single distribution channel.
Your friends with 700EUR phones aren't really all of the market and there's still enough devices out there that will not successfully install a 30+MB APK. And that's not even talking about how wasting users storage for things he doesn't need (just because you're a bit lazy) is just... wrong.
I think I'd rather just detect the issue and throw up an error telling the user that they've managed to install an apk built for the wrong architecture and need to install a different apk ...
As far as I can tell, their ReLinker solution is only a workaround to the installation problem.
Actually, now that I think of it, I can see a business requiring employee devices to be flashed with a set of apps but not wanting to put the effort to actually check that it'll work. In that case the developer should determine if the user is an individual or a company and in the later case sell them a contract for support.
I guess it should be pretty simple to add a "wrong version for your device" killscreen to an app, once you realize it's a problem.
You could load the lib from a remote server after install if you need to save space but if we are talking about saving 1-3 MB I'd definitely save myself the hassle and just pack the libs for all architectures in one apk file.
The article acknowledges that the root cause was an existing bug in Package Manager.
> We started to log the installer package name in our crashes and quickly figured out that, yes, users were installing the app from various sources, and each new UnsatisfiedLinkError was coming from a manually installed app where the user mistakenly installed the wrong flavor for their device’s architecture.
It is probably still blamable on bad design from Android, that it's possible to successfully install and launch an app that can only possibly use some of the code it requires (or maybe the app devs need to do something to indicate the native libraries are absolutely required?)
When a major bug is discovered in Android, first, Google fixes it and published the code. This is usually done quickly. Second, the phone manufacturers take that fix and incorporate it into their own Android build process with all their extra layers (HTC Sense, Samsung TouchWiz, etc). This second step takes anywhere from a few weeks to infinity (aka it never happens). Third, the carrier takes the manufacturers build and adds their own cruft to it, maybe tests it, and then pushes it out to their customers as an over the air (OTA) update. This third step takes anywhere from a month to infinity (aka it never happens).
Due to the interference of manufacturers and carriers, I would not recommend using Android on anything other than a Nexus device purchased directly from Google or a retail/online store. Even a Nexus, when purchased from a carrier, won't get updates as quickly as it should (speaking from experience with my Nexus 6 and T-Mobile).
Is this a euphemism for piracy? Where are these users getting the app?
Plus, google might block downloads in some countries.
There are a number of sites that offer apk downloads for free apps: see http://apkpure.com/, https://apps.evozi.com/apk-downloader/, or http://apk-dl.com/. See also http://www.makeuseof.com/tag/download-apk-google-play-bypass... for more reasons people might not want to use Google Play.
kudos to the devs for making the effort to workaround the issues though, its quite a heroic effort imo.
https://github.com/yahoo/ygloo-ymagine/blob/master/src/com/y...
Here's another fun Android / PackageManager behavior - Android doesn't kill an app before upgrading it (unlike on iOS). You may think this is a feature, except that after the upgrade the PackageManager is now out-of-sync with the running code. So for example, say v1 of the code is still running after an upgrade to v2, and the code calls getPackageInfo() in order to find out say, its versionCode. The running code will erroneously think it's v2.
Google needs to start doing the same thing or something similar. I have seen a fair share of broken stuff. Something even as basic as a ListView was horrendously let loose in a middle of a refactor between JB and L.