Android NDK - multlib support using gradle

2.9k views Asked by At

My question is directed towards native Android development for 64bit Android systems.

I am looking for a way to configure the support of 32bit compiled native libraries at a 64bit Android system using the gradle build system. The libraries the application should use are only available as 32bit build. It would be very time consuming and error prone to port these libraries to 64bit.

Hence, I want to configure gradle to deploy these prebuilt 32bit binaries and to use a 32bit version of the Android application as well.

The current configuration leads to the following error:

 E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: <application_name>, PID: 2170
    java.lang.UnsatisfiedLinkError: 
dalvik.system.PathClassLoader
[DexPathList[[zip file "/data/app/<application_name>/base.apk"],
nativeLibraryDirectories=[/vendor/lib64, /system/lib64]]] 
enter code here`couldn't find "libmynativelibrary.so"
    at java.lang.Runtime.loadLibrary(Runtime.java:366)

It seems as though the PathClassLoader looks in the wrong directories. I checked the provided apk file and it is lacking the libraries. There is no lib folder inside the apk. The build system does not seam to include the 32bit libraries. Since there is only one prebuild version for armv7 these libraries are in app/src/main/jnilibs folder.

I have to add that this setup works perfectly for any 32bit Android system. I tried it with the emulator and a physical device before.

How should one activate the multiarch 32/64bit support using gradle? Or how is it possible to deploy a 32bit application to a 64bit Android system using Android Studio/gradle?

I searched the web and found one link concerning the topic, but it is referring to the older build system: https://source.android.com/source/64-bit-builds.html. I do not know how to adopt the description to gradle.

I am using Android Studio (Build: 141.1989493, June 6, 2015). The project/build.gradle is untouched. The app/build.gradle file looks like this:

apply plugin: 'com.android.application'

android {
    compileSdkVersion 22
    buildToolsVersion "22.0.1"

    defaultConfig {
        applicationId "<application_name>"
        minSdkVersion 1
        targetSdkVersion 22
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'),
                                                 'proguard-rules.pro'
        }
        debug {
            debuggable true
        }
    }

    productFlavors {
        armv7 {
            ndk {
                abiFilter "armeabi-v7a"
            }
        }
        fat
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
}
2

There are 2 answers

1
Matthias Scholz On

In order to get 32bit application deployment for 64bit Android system one needs to define a armv7 productFlavor and a subfolder inside the jniLibs folder naming the corresponding architecture.

Product flavor definition in app/build.gradle:

android {
   productFlavors {
      armv7 { ndk { abiFilter "armeabi-v7a" } }
      fat
   }
}

Native library structure: 

app/src/main/jniLibs/armeabi-v7a
0
ph0b On

The concept of mulilib is only for projects that are part of an Android system build and you shouldn't set the android:multiarch option as you only have 32bit libs since this option is only for apps that are providing both 32 and 64bit libraries to other installed application.

64-bit Android systems support 32-bit applications directly. You only need to properly package your app, with your .so files inside lib/(armeabi-v7a,x86,...) of the APK, as for any Android devices.

At the install time, the libs of the architecture that is preferred by the device will be installed. ie: if there is no x86_64 folder, the x86 libs will be installed / if there is no arm64-v8a folder, the armeabi-v7a libs will be installed, and your app will run in 32-bit mode.

If you don't have anything under lib, that means Android Studio doesn't know about your .so files. By default it will look for them inside jniLibs/(armeabi-v7a,x86,...), hence you should place them there or change sourceSets.main.jniLibs.srcDir to the directory of your choice.