In my application I use renderscript which has native code for x86, armeabi-v7a and mips (~2.7Mb each). Also I read that the mips architecture has just a few devices. So I'd like to bundle my application in two APKs: universal (eg. x86 and armeabi-v7a) and mips. I found that split section helps to create apk for mips, but universal apk still contains mips architecture. So my question is how to exclude abi from result apk?
Thanks
You can try setting up another flavor that contains everything but MIPS. In the build.gradle file from one of the test projects that are part of the Android Gradle plugin sources, I found this:
apply from: "../commonHeader.gradle"
buildscript { apply from: "../commonBuildScript.gradle", to: buildscript }
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion = rootProject.ext.buildToolsVersion
productFlavors {
x86 {
ndk {
abiFilter "x86"
}
}
arm {
ndk {
abiFilters "armeabi-v7a", "armeabi"
}
}
mips {
ndk {
abiFilter "mips"
}
}
}
}
It looks like their arm flavor basically includes the two common ARM ABIs. You could probably define an "universal" flavor containing x86 and armeabi-v7a.
They have another test project, whose build.gradle contains:
splits {
abi {
enable true
reset()
include 'x86', 'armeabi-v7a', 'mips'
}
}
You might be able to use something similar, and drop the mips from there.
Related
I am attempting to build all ABIs for my project but would only like to package a subset of them into my app. For example, I would like to build "x86", "x86_64", "armeabi-v7a" and "arm64-v8a" but only package "x86" (for example).
Reading this document (https://developer.android.com/studio/projects/gradle-external-native-builds.html#jniLibs) under section "Specify ABIs", it seems very possible using the snippet they provided as an example. However, this does not seem to be working for me.
My code snippet is as follows.
android {
defaultConfig {
ndk {
abiFilters 'armeabi-v7a'
}
externalNativeBuild {
cmake {
abiFilters 'armeabi-v7a', 'x86'
}
}
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
In the snippet above, from my understanding of the document, it should build both armeabi-v7a and x86, but only package armeabi-v7a in my APK. This is not working though.
I am using Android plugin 3.1.0 and NDK 16.1.4479499
what you are looking for, is controlled by splits.
splits {
abi {
enable true
reset()
include 'armeabi-v7a'
universalApk false //don't generate an additional APK that contains all the ABIs
}
}
I have a large number of gradle modules I use to build my android applications and libraries. My application is decomposed into multiple java & C++ libraries. Each module might be a java library, or an APK project. For each module representing an APK, I have a build.gradle which specifies various productFlavors sections that control how to build them. Example:
flavorDimensions "mode"
productFlavors {
arm {
dimension "mode"
externalNativeBuild {
ndk { abiFilters "armeabi-v7a" }
}
}
x86 {
dimension "mode"
externalNativeBuild {
ndk { abiFilters "x86" }
}
}
full {
dimension "mode"
externalNativeBuild {
ndk { abiFilters "x86", "armeabi-v7a" }
}
}
}
What I'm trying to avoid is duplicating the above configuration in each leaf build.gradle that represents an APK output. How can I store the product flavors at the root level and somehow have those transitive to the leave build.gradle files so I do not need to duplicate them?
The support library does something very similar, and you can see their method here (in particular, the SupportLibraryPlugin).
At a high level the strategy is to create a Gradle plugin in your buildSrc directory that you apply to each of your projects. This plugin will apply the common configuration.
Your plugin might look something like this:
[project]/buildSrc/src/main/groovy/com/example/ConfigurationPlugin.groovy
class ConfigurationPlugin implements Plugin<Project> {
#Override
public void apply(Project project) {
LibraryExtension library = project.extensions.findByType(LibraryExtension.class);
library.flavorDimensions "mode"
library.productFlavors {
arm {
dimension "mode"
externalNativeBuild {
ndk { abiFilters "armeabi-v7a" }
}
}
x86 {
dimension "mode"
externalNativeBuild {
ndk { abiFilters "x86" }
}
}
full {
dimension "mode"
externalNativeBuild {
ndk { abiFilters "x86", "armeabi-v7a" }
}
}
}
}
}
[project]/builSrc/build.gradle
apply plugin: 'groovy'
repositories {
google()
}
dependencies {
compile 'com.android.tools.build:gradle:3.0.0-beta7'
}
Library module build.gradle:
apply plugin: 'com.android.library'
apply plugin: ConfigurationPlugin
android {
// ...
}
You can reference another Gradle project within your project using ':project-name', e.g. compile ':pluginproject'. You'll also want to update settings.gradle to include the other project. The project will be built when it is needed to apply the plugin.
I am trying to build universal apk for all architectures. Here is my project structure:
-App
-appModule
-libraryModule
-libs
-armeabi
-lib.so
-src
-java
-jni
Here is my gradle file for libraryModule:
apply plugin: 'com.android.library'
// http://stackoverflow.com/questions/28485309/how-to-build-single-apk-with-andoid-ndk-and-gradle
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
ndk {
moduleName "ProxyResolver" // <-- This is the name of AndroidProxy native module
stl "gnustl_shared"
cFlags "-std=c++11"
abiFilters = ['armeabi']
ldLibs (projectDir.absolutePath + "/libs/armeabi/libresolver.so")
}
}
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
As you can see the path for library is hardcoded. And right now it works on arm-v7 processors. But i need to add support of x86 without adding a flavor
I guess:
ndk {
moduleName "resolver"
stl "gnustl_shared"
cFlags "-std=c++11"
abiFilters = ['armeabi','arm-v7']
}
And remove
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
Setting abiFilters in your defaultConfig only adds information to the app's capabilities (only useful for the Installer, i.e. the Installer gives an error when the device you try to install to is not compatible) and does not change which binaries are added to the final apk, see also https://stackoverflow.com/a/39445685/1827156.
I guess what you want to accomplish is to have different apk for different architectures. This is a common usecase, i.e. to reduce build sizes. You can accomplish this by using splits in your app's build.gradle. Please refer to https://developer.android.com/studio/build/configure-apk-splits.html.
I highly recommend https://www.neotechsoftware.com/blog/native-libraries-part-i-common-pitfalls (I'm not the author).
Note on working with libraries/aars:
However, there's one major pitfall when you work with libraries (aar instead of apk). Imho, you can't (automagically) create different ABI-specific aars. Instead, you create aars containing the binaries for all ABIs. When adding the aar to an android app, you specify splits in the apps build.gradle as mentioned above.
I'm trying to include mupdf as an android library module with precompiled .so binaries into my project.
I have an application module which includes my library module like so.
dependencies {
compile project(':mupdf')
}
In my mupdf library module I have my compiled binaries like so.
mupdf
- jniLibs
- arm64-v8a
libmupdf.so
- armeabi
libmupdf.so
- armeabi-v7a
libmupdf.so
- x86
libmupdf.so
- x86_64
libmupdf.so
My build.gradle for the mupdf library project:
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
publishNonDefault true
productFlavors {
x86 {
ndk {
abiFilter "x86"
}
}
x64 {
ndk {
abiFilter "x86_64"
}
}
arm {
ndk {
abiFilter "armeabi"
}
}
arm_v7a {
ndk {
abiFilter "armeabi-v7a"
}
}
arm64_v8a {
ndk {
abiFilter "arm64-v8a"
}
}
fat
}
}
dependencies{
compile project(':core')
}
The problem is soon as I add the product flavors my app doesn't compile because it doesn't find any of the java files from the mupdf module.
If I delete the product flavors part from the gradle file it compiles. But it crashes at runtime because it can't resolve/load the libmupdf library.
You can do this without product flavors. Just remove them and call System.loadLibrary("mupdf") on startup/at some point before the library is used. This call will figure out which native lib to use for the current devices architecture.
Indeed I have to build a fat module for the .aar library and apply the productflavors in my app.gradle.
I was missing this in my library's build.gradle
sourceSets.main {
jni.srcDirs = [] // This prevents the auto generation of Android.mk
jniLibs.srcDir 'src/main/jni'
}
Without this no methods were able to be resolved.
I have an android APK that use a native library (snappydb).
The native libraries takes a lot of spaces, so I want to keep only the snappydb for armeabi-v7a architectures?
I know it's not 100% safe to remove snappydb for other architectures, so my question is: how unsafe it is? (how many devices/users will I lost?)
Just for reference, the minimal sdk version that my app support is 16 (JELLY_BEAN).
I suggest using Gradle's productFlavors to produce different APKs per ABI, as some ABI may include some assembly code optimization (SSE4, SSE5, Arm Neon etc,)
android {
...
flavorDimensions "abi", "version"
productFlavors {
freeapp {
flavorDimension "version"
...
}
x86 {
flavorDimension "abi"
...
}
}
}
Or if you're using the experimental Gradle plugin
'com.android.tools.build:gradle-experimental:0.1.0'
android.productFlavors {
create ("arm7") {
ndk.abiFilters += "armeabi-v7a"
}
create ("arm8") {
ndk.abiFilters += "arm64-v8a"
}
create ("x86-32") {
ndk.abiFilters += "x86"
}
// for detailed abiFilter descriptions, refer to "Supported ABIs" #
// https://developer.android.com/ndk/guides/abis.html#sa
// build one including all productFlavors
create("fat")
}
You will probably not gain too much from arm-v7a optimization, and currently there is no compelling reason to include 64-bit build. But MIPS and X86 owners will thank you if you keep their devices covered.