background

64-bit applications perform better and will run on future devices that only support 64-bit architectures. Currently, various application markets have also put forward requirements for 64 adaption.

Google Play:

Starting August 1, 2019, apps distributed on Google Play must support 64-bit architecture.

Domestic:

Xiaomi App Store, OPPO App Store and Vivo App Store have been notified

  • End of December 2021: Existing and newly released apps/games will be required to upload APK packages containing the 64-bit package (support both in-rack and 32-bit compatible versions, no longer accept 32-bit only APK packages)
  • End of August 2022: Systems with 64-bit hardware support will only receive APK packages with 64-bit versions
  • End of 2023: Hardware will only support 64-bit APK, 32-bit applications will not run on terminals

32 bits and 64 bits

Each CPU type corresponds to an Application Binary Interface (ABI). Common ABI types include Armeabi, Armeabi-v7A, ARM64-V8A, x86, and x86_64.

  • Armeabi: the 5th and 6th generation ARM processor, which is used in early mobile phones and can be phased out
  • Armeabiv-v7a: 7th generation and above ARM processor. It is used by most Android devices manufactured since December 2011
  • Arm64-v8a: eighth-generation, 64-bit ARM processor
  • X86: tablet, simulator used more
  • X86_64:64-bit tablet

For example, arm64-V8A cpus can run ARmeabi-V7A sO, and vice versa. This is why many apps now only include armeabi-V7a packages but can run on the latest cpus. Apps that currently only include Armeabi or Armeabi-V7a will no longer run if future cpus are no longer compatible with older architectures.

What about both architectures? On machines that support 64-bit systems, there will be two Zygote(one 32-bit and one 64-bit) processes running at the same time. PrimaryCpuAbi is determined when the APP is installed according to the supported architecture in the lib directory and the CPU type of the machine. At startup, the child process is fork out from the 64-bit or 32-bit Zygote process according to the value of primaryCpuAbi determined at the time of installation. If it forks from 64, it runs in 64-bit mode.

Check whether the 64-bit requirements are met

If you don’t use any native code, you’re already 64-bit. How do I check if I’m using native libraries? A faster way is to use the APK profiler provided with Android Studio. Build > Analyze APK…

If you only have armeabi or armeabi-v7a in your lib folder, you only support 32 bits, not 64 bits. If you also have the arm64-V8A folder, it indicates that there is a 64-bit native library, whether it has the same functionality and quality as 32-bit, still need to test.

Quickly find native libraries that do not support 64-bit

In-app native libraries generally come from three sources:

  • Third-party libraries
  • So files in the project
  • C/C++ source module

Many third-party libraries support both 32 and 64 bits, but some do not. How to find out which libraries or files are not supported? If your project has a large number of so files, it is difficult to find them visually. A Gradle script is provided to quickly and easily find libraries that do not support 64 bits. Add the following code to the end of the main module build.gradle:

tasks.whenTaskAdded { task ->
    if (task.name=='mergeDebugNativeLibs') {
        task.doFirst {
            println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =")
            def v7a = []
            def arm64 = []
            it.inputs.files.each { file ->
                if (file.absolutePath.endsWith("/jni")) {
// println("==========" + file.absolutePath)
                    if (file.isDirectory()) {
                        file.listFiles().each { soFileDir ->
                            if (soFileDir.absolutePath.contains("armeabi-v7a")) {
                                if (soFileDir.isDirectory()) {
                                    soFileDir.listFiles().each {
                                        println(it.absolutePath)
                                        v7a.add(it.name)
                                    }
                                }
                            }
                            if (soFileDir.absolutePath.contains("arm64-v8a")) {
                                if (soFileDir.isDirectory()) {
                                    soFileDir.listFiles().each {
                                        println(it.absolutePath)
                                        arm64.add(it.name)
                                    }
                                }
                            }
                        }
                    }
                }
            }
            println("v7a size: ${v7a.size()}")
            println("arm64 size: ${arm64.size()}")
            println("so in v7a, but not in arm64:")
            v7a.each {
                if(! arm64.contains(it)) { println("$it")
                }
            }
            println("= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =")}}}Copy the code

Then execute.\gradlew assembleDebug, which can be replaced with the Flavor in the actual project. The Demo project output is as follows:

> Task :app:mergeDebugNativeLibs ========================================================== XXX \ 5 d0e00f6a703ec622708978bebed0322 \ MMKV - static - 1.2.8 \ jni \ arm64 - v8a \ libmmkv so XXX \ 5 d0e00f6a703ec622708978bebed0322 \ MMKV - static - 1.2.8 \ jni \ armeabi - v7a \ libmmkv so XXX \ 7206 efbbb5863dbe5969c1c384b81177 \ openDefault - 4.2.7 \ jni \ armeabi - v7a \ libweibosdkcore. So XXX \ ccd11b53aab95a933b06ef9e74f9fb44 \ sentry - android - the NDK - 3.1.3 \ jni \ arm64 - v8a \ libsentry - android. So XXX \ ccd11b53aab95a933b06ef9e74f9fb44 \ sentry - android - the NDK - 3.1.3 \ jni \ arm64 - v8a \ libsentry. So XXX \ ccd11b53aab95a933b06ef9e74f9fb44 \ sentry - android - the NDK - 3.1.3 \ jni \ armeabi - v7a \ libsentry - android. So XXX \ ccd11b53aab95a933b06ef9e74f9fb44 \ sentry - android - the NDK - 3.1.3 \ jni \ armeabi - v7a \ libsentry so v7a size: 4 arm64 size: 3 so in v7a, but not in arm64: libweibosdkcore.so ==========================================================Copy the code

From the output, you can quickly see which ones already support 64-bit, find which so files don’t, and where they are.

Demo project see: github.com/callmepeanu…

Adaptation of 64

After finding the list of so files that do not support 64 bits, if it is a third-party library or imported so file, you need to check whether there is a new version that has been adapted to 64 bits, or obtain a version that supports 64 bits from the provider. If it is compiled from C/C++ source code in your own project, you need to do the adaptation of 64-bit architecture in the compilation options and source code level and generate the corresponding architecture so library file.

packaging

It is possible to pack all the SUPPORTED ABI’s SO into a single package, so that one installation package can fit all devices, but the disadvantage is that the package size can increase, especially if there are many native libraries. Currently, the application market provides the ability to upload 32-bit compatible packages and 64-bit packages separately, so the ability to build multiple APKs can be used to print packages that support different ABI’s. The application market distributes corresponding packages according to the CPU type of users’ phones, reducing the size of packages downloaded by users. To support building multiple APKs, add the following configuration to build.gradle:

android {
	
	...
		
    splits {
        abi {
            enable true
            reset()
            include 'armeabi-v7a'.'arm64-v8a'
            universalApk false}}}Copy the code

The generated installation package is shown below:

Reference:

  • Developer.android.com/distribute/…
  • www.fresco-cn.org/docs/multip…
  • www.infoq.cn/article/8wa…
  • Dev.mi.com/distribute/…
  • Dev.mi.com/distribute/…
  • Developer.android.com/studio/buil…