How to target different Android architectures?

15,655

Solution 1

I am currently using the OpenCV (OpenCV4Android) library which does not use the NDK (there is no C or C++ code). However, there are .so files for armeabi, armeabi-v7a, mips, and x86.

As immibis put it, if there are .so files, then it is using the NDK.

If I try to run the app on a device that doesn't have that device's architecture's .so file included, it crashes, whereas if I have it's .so file included, it works.

That depends upon the device. Many x86 devices have libhoudini, which can run ARM NDK binaries, albeit more slowly than they would run native x86 binaries. Similarly, an armeabi-v7 device can run armeabi NDK binaries, though perhaps more slowly, particularly if floating-point processing is used.

Therefore, I am wanting to release multiple APKs to different device architectures to reduce the file sizes. From what I've seen, this can only be done in the Application.mk file, but my library does not have one.

The Application.mk file only controls what gets compiled, not what gets distributed.

Is there another way to target different Android architectures?

Use Gradle for Android, perhaps in conjunction with Android Studio, and the abi split:

android {
  ...
  splits {
    abi {
      enable true
      reset()
      include 'x86', 'armeabi-v7a', 'mips'
      universalApk true
    }
  }
}

The abi closure in the splits closure:

  • opts into having different APK files per CPU architecture

  • sets up a whitelist of the architectures that you want

  • also requests a "universal APK" that contains all of the architectures, for use with distribution channels that do not support separate APKs by architecture

The result of your build will be separate APKs by CPU architecture, plus the universal one.

Solution 2

Each apk for the application should have unique version code specified by android:versionCode. Some x86 devices can run ARMv7 binaries. So, to avoid a case of ARMv7 apk getting downloaded/used in x86 device ( and similar scenarios for other architectures ), you should order the version codes. For e.g., order the version codes so that, the x86 APK has a higher version code than ARMv7. More on versioning at this link.

A build.gradle sample for creating unique version coded apks for each architecture of your choice is shared by ph0b at github. Copying the same below.

splits {
        abi {
            enable true
            reset()
            include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a' //select ABIs to build APKs for
            universalApk true //generate an additional APK that contains all the ABIs
        }
    }

    // map for the version code
    project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]

    android.applicationVariants.all { variant ->
        // assign different version code for each output
        variant.outputs.each { output ->
            output.versionCodeOverride =
                    project.ext.versionCodes.get(output.abiFilter, 0) * 1000000 + android.defaultConfig.versionCode
        }
    }

Suggestion: Android multiple apk support documentation suggests to not use multiple apks if apk size is less then 50mb.

You should generally use multiple APKs to support different device configurations only when your APK is too large (greater than 50MB) due to the alternative resources needed for different device configurations. Using a single APK to support different configurations is always the best practice, because it makes the path for application updates simple and clear for users (and also makes your life simpler by avoiding development and publishing complexity).

Solution 3

I do not recommend to use this pattern to build your Build number. ARCH - BUILD, because if one day you want to come back to one APK, you will have to increase your versionCode a lot. instead you can follow this pattern: BUILD - ARCH

android.defaultConfig.versionCode * 100 + project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0)

exemple for build 74 the build number will be: 7402 - armeabi-v7a 7408 - x86

Share:
15,655
AggieDev
Author by

AggieDev

I specialize in Android.

Updated on July 22, 2022

Comments

  • AggieDev
    AggieDev almost 2 years

    I am currently using the OpenCV (OpenCV4Android) library which does not use the NDK (there is no C or C++ code). However, there are .so files for armeabi, armeabi-v7a, mips, and x86. If I include all of these in the project, the app size is 30mb, whereas if I include only 1, the app size is only 9mb. If I try to run the app on a device that doesn't have that device's architecture's .so file included, it crashes, whereas if I have it's .so file included, it works.

    Therefore, I am wanting to release multiple APKs to different device architectures to reduce the file sizes. From what I've seen, this can only be done in the Application.mk file, but my library does not have one. Is there another way to target different Android architectures?