I have been distributing my app with armeabi and armeabi-v7 versions of native binary but recently started to get a lot of UnsatisfiedLinkError errors where "somehow" one of the native binaries (app has few) isn't extracted/copied on install. I can't reproduce it but it looks like this is due to size of the app being near to 8 MB.
I want to stop including armeabi-v7 in the app to save near enough 2 MB and done some tests on 3 devices I have. Everything seems to be working. I also noticed (for example) Dropbox only distributes armeabi.
Would you advise against it? And yes, native binary does some number crunching and encoding but there is no optimization in build script?
8 MB should not be a problem. However, you can safely drop armeabi-v7a if you verify that it is not performance bottleneck.
Alternatively, you can use the multi-APK approach to make user downloads smaller. The official site recommends: You should generally use multiple APKs to support different device configurations only when your APK is too large (greater than 50MB). You should carefully follow the version code guidelines if you choose this route.
Related
I am working with Xamarin Forms and I published the Android app ad-hoc to disc.
What I would like to do is to give the apk to some people to test by uploading it to a web site I have so they can download it. Here's what was created:
com.xx.xx-arm64-v8a.apk
com.xx.xx-armeabi-v7.apk
com.xx.xx-x86_64.apk
com.xx.xx-x86.apk
com.xx.xx.apk
My question is twofold. Why does it create four apps and which of those should I give to the person? I assume it's okay to give the last in the list but if that's the case then why are the others created?
I also heard something about a new feature with Android that would allow smaller builds and just let a person download the build that is needed for their device. Can someone tell me if I could use that with these apks and if so how I would do it.
Thanks
Here are the list of options that I have selected:
Please open your Android Options, If you enable the Generate one package (.apk) per selected ABI selection, you will get serveral .apk file. If you want to generate one .apk file, just unselect it like following screenshot.
If you want to enable the Generate one package (.apk) per selected ABIselection. you can give the .apk file by Users' device(CPU Architectures).
Xamarin.Android supports the following architectures:
armeabi – ARM-based CPUs that support at least the ARMv5TE instruction set. Note that armeabi is not thread-safe and should not be used on multi-CPU devices.
Note
As of Xamarin.Android 9.2, armeabi is no longer supported.
armeabi-v7a – ARM-based CPUs with hardware floating-point operations and multiple CPU (SMP) devices. Note that armeabi-v7a machine code will not run on ARMv5 devices.
arm64-v8a – CPUs based on the 64-bit ARMv8 architecture.
x86 – CPUs that support the x86 (or IA-32) instruction set. This instruction set is equivalent to that of the Pentium Pro, including MMX, SSE, SSE2, and SSE3 instructions.
x86_64 CPUs that support the 64-bit x86 (also referred as x64 and AMD64) instruction set.
If you want to know more details about CPU Architectures, you can refer to this thread.
https://learn.microsoft.com/en-us/xamarin/android/app-fundamentals/cpu-architectures?tabs=windows
while you are creating an apk Please make sure your Architecture should be armeabi-7a and armeabi-v8a in Project Properties - > Android Options -> Advanced.
after that Clean Solution.
than Please go for .apk Archive it will create simple Signed Apk which you can distribute.
Hope it helps.
I have an Android app that uses some JNI code. Long story short (pun intended), it is nearly impossible to convert the JNI libraries to 64-bit as it would require a lot of changes. The code (both Java and JNI) works nicely on armeabi-v7a architecture.
The libraries are being loaded using loadLibrary. When I attempt to run my app on a Nexus 6, the app loads fine. As soon as loadLibrary is executed, the app crashes with the error described here.
The problem, as I understand it, is that when executing on Nexus 6, the app builds as arm64-8a. But the libraries are not built for arm64-8a (as the 64-bit version has issues I mentioned at start of the question).
My question is, can I force arm64-8a devices to also run armeabi-v7a code? How do I force my app apk to be armeabi-v7a so it is only 32-bit regardless of device?
Yes, arm64-v8a devices can also run armeabi-v7a code.
When the APK is installed, the installer checks if the package contains libraries in the official directories, and marks the activity as 32 or 64 bit depending on the outcome.
If it finds libraries in lib/arm64-v8a within the APK (normally taken from the directory libs/arm64-v8a in the build directory), it will be marked as 64 bit, and will ignore all other directories. If it finds libraries in lib/armeabi-v7a or lib/armeabi in the APK, the process is marked as 32 bit. If there's no native libraries in any of these, the installer assumes that the application doesn't use native code at all and is free to run it in either mode, in practice in 64 bit mode.
Now if you do ship some, but not all, libraries in 64 bit mode, the process will be launched in 64 bit mode and will be unable to load the 32 bit libraries (which won't even be installed). In this case, you must avoid bundling any 64 bit libraries unless all of them are available.
Or you don't use the official libs directory but install your libraries some other way (e.g. by downloading them at runtime or keeping them in e.g. assets), the system has no idea that your process wants to run libraries in 32 bit mode (at which point it is too late to switch to the other mode). In these cases, make sure to include at least some dummy library in the normal/official way, in order to flag the application as 32 bit.
See https://stackoverflow.com/a/33919454/3115956, https://stackoverflow.com/a/27713998/3115956 and https://stackoverflow.com/a/35450911/3115956 for answers to similar issues.
I have some libraries that use native components, the libraries are built with NDK for 32 bit Arm architectures.
now we have 64-bit processors on modern devices, so I'm wondering if the libraries will work. In my situation, I don't have the source code files of the native library, just the SO files, I can't build them for 64-bits.
So will the 32-bits libraries run on 64-bits processors? or I have to re-build them?
**
EDIT
**
In my scenario I have the following:
1- I distribute the APK manually, didn't publish to Google Play yet.
2- The project has two native libraries, one with 64 & 32-bits support and the other with 32-bits only.
Is there a way to make the application work on 64-bits devices without having to publish to Google Play for now? can I remove the 64-bits libs to enforce the package manger to load the 32-bits ones?
The 32 bits libraries will work just fine on 64 bits processors.
As long as the libraries get installed the right/official way (i.e., not manually downloaded or extracted from some nonstandard part in the APK, but packaged properly in the APK), the package manager will detect that the process uses 32 bit libraries, and the process should be started in 32 bit mode. If not, the process will be started in 64 bit mode, and later will be unable to load 32 bit libraries. (If your APK would contain some .so files, but not all, in 64 bit mode, it would only install them, and the process would be launched in 64 bit mode. So unless all .so files are available for a specific ABI, don't include any of them).
So if you have a 64 bit version of one of the native libraries, just remove that and only ship the 32 bit version, until you have 64 bit versions of all of them.
I have a few native libraries that are fairly big and bloating the application binary size. I looked into APK splitting but maintaining and QAing multiple APKs is not something I want to do.
So I'd like to exclude unused architectures in my release build flavour using the ndk.abiFilters Gradle property. (The debug builds I want to leave alone so that I can run the HAXM-accelerated emulator on x86).
I was thinking of just having armeabi-v7a and arm64-v8a in my release flavour, but I'm not sure whether it is worth worrying about the market share of the other architectures I'm dropping. After a lot of looking around I cannot find any reference to market share of ARMv6 (armeabi), MIPS, x86 or x86_64. My intuition tells me that the latter three are almost non-existent, but I'm not sure about ARMv6.
I found this link on a forum that has a list of phones that use various architectures. Is there something more reliable somewhere? Maybe with % of users similar to the Android version dashboard?
Anything else I may miss if I just build my native libs for armeabi-v7a and arm64-v8a (or armeabi, armeabi-v7a and arm64-v8a)?
First off, if you're worring about binary size, you don't really need arm64-v8a, all those devices can run the armeabi-v7a binaries just fine. Only if you really need to cram the last extra performance out of it, it might be worthwhile.
As for armeabi and ARMv6; Android itself doesn't officially support it any longer, since Android 4.4 (October 2013) - and since Android 4.0 it should be much less common (from that version, AOSP source requires modifications to still build for ARMv6). So in practice, if you aren't supporting versions below 4.4, you can drop that one without any significant loss.
Also, for x86; many of those devices ship with surprisingly decent emulation of arm binaries, so those can manage with the armeabi-v7a version just fine as well.
EDIT: The above was written in 2015; these days Play Store requires that apps include support for arm64-v8a. But these days the next question is more about whether you need to include armeabi-v7a at all, or if the market share of 32 bit devices is small enough to drop support for.
Including additional architectures will no longer have any impact on the binary size when using app bundles, as in that case Google Play will serve each device only the binaries that apply to that particular device. Not only that, but also application updates will be way smaller and faster.
Leaving the previous information for projects still not using app bundles:
Unfortunately, the Android Dashboard, as useful as it is, does not provide architecture information, nor does Google Analytics.
The Unity statistics used to provide statistics per architecture and CPU features. Note, however, that these are not general statistics, but only cover users of Unity applications/games. The information doesn't seem to be available in a public link anymore, so I have replaced the direct links with the latest snapshots in archive.org.
I was stuck with this problem when using Mapbox, then later found this article which was very useful.
Based on the below picture you just need armeabi-v7a and x86. Then based on Jose Gómez answer, I only added armeabi-v7a and didn't have any problem at all.
So add this line to your app.gradle
android {
defaultConfig {
//other configs
ndk {
abiFilters "armeabi-v7a"
}
}
}
If you're still worried about 2% - 3% of those who use x86 architecture, like ASUS ZenFone and lenovo phones then use this config instead in app.gradle
ndk {
abiFilters "armeabi-v7a", "x86"
}
Also for genymotion emulators you should use x86 architecture
UPDATE
If you get this error while publishing the apk in play store
Then use this
ndk {
abiFilters "armeabi-v7a", "arm64-v8a"
}
And finally, I suggest you use app bundle for releasing the APK
When I read #mstorsjo answer I was a little bit confused how to really use only one (or two) native libs, even though it's quite simple and straightforward. Therefore, I will give here an example and some more explanation (based on my further research).
For each supported architecture we have to create a specific folder in the jniLibs folder and drop the .so file there. As an example, for supporting armeabi-v7a (32bit) and arm64-v8a (64bit):
|--app
|--|--src
|--|--|--main
|--|--|--|--jniLibs
|--|--|--|--|--armeabi-v7a
|--|--|--|--|--|--.so Files
|--|--|--|--|--arm64-v8a
|--|--|--|--|--|--.so Files
With armeabi-v7a you support more than 90% of the available devices, but since it is 32bit architecture, running it on 64bit devices will result in an loss of performance (20-30%) {1}. For each specific case it can be quite handy to check the actual amount of supported devices, which can be done within the Google Play Console in the Release management > Device catalog section, by specifying ABI as filter.
Attention
When you don't add binaries for all architectures you have to be aware of the following:
If your app contains any other native libraries, you'll have to make sure you only have the same versions of them as well. That is due to Android demanding that all loaded native libraries be built for the same architecture. For example, if the first native library loaded is armeabi-v7a, Android will look ONLY for armeabi-v7a libraries on all System.loadLibrary() calls after that. If it doesn't find that exact architecture, it'll throw the java.lang.UnsatisfiedLinkError exception. {1}
I ran into this problem because some of my dependencies used native libraries, whereby armeabi-v7a couldn't be loaded anymore.
My app size has more than doubled from 21MB to 44MB when ported over from android to ios and compiled in xcode (default settings with a few imported frameworks for admob and chartboost). Any ideas on why this is and if there is any way to reduce it?
I've gone through my texture/audio settings after converting the project, and all of them seem to be the same, so im not sure on why the sudden increase.
EDIT:
a bit more info:
-unity target device (iphone + ipad)
-Target OS - 5.1
Xcode
-architectures - armv7
-Valid architectures - arm64 arm7 arm7s
-base sdk - IOS 8.1
-supported platforms - iphoneos
everything else is pretty much default
well. its a very general question but you should know some important things.
first one is when you export your game for a platform the unity add the assembly files and system files and... for that platform. for example if you export and empty project for android you will see its about 9mb. it maybe different for ios for pc and...
second one is how package format of these platforms are compressed. different compression algorithm they use, the different size of final output will be.
there was a same problem for me that i wanted to avoid using data files with my apk file. there is not much problem with more file size untill it doesnt effect you game/program quality.
there is a topic on unity website about this problem.
http://answers.unity3d.com/questions/233563/transferred-game-from-android-to-ios-why-is-the-fi.html
its may because you made output for both arm6 and 7
For those interested, just found out that depending on your project, your development build may be significantly larger than your actual release build. Mine was 44.9MB when testing on my iphone, but the actual release build which needed to be submitted to itunes was only 28MB. (Also the estimate button in your archives window may also show higher numbers sometimes, even for your release build)
From reading, I found out that this could be reduced further, however I decided to stop here and go with this build for now as 28 mb seems ok.
Keep in mind that when you just build with Xcode and check the size of the produced .APP, that is not the one will be uploaded to AppStore. This is uncompressed unlike .APK on Android or the .IPA on iOS which is compressed by ZIP actually (just like .JAR).
On my quick test I have compiled a minimal project with only a text label on it and got a 43MB .APP. When I zipped it up manually, I got around 9.2MB .ZIP file, and when I have done an Archive build and exported that to a folder I have got a 7.4MB .IPA file... Obviously when you do an Archive (Final Release) build that is not only a dumb zipping it up process. Xcode will strip off every unnecessary thing from your executable, hence the smaller footprint...
Anyways, I think the file size is acceptable in my opinion.