Search code examples
opencvgradleandroid-ndkjava-native-interfaceunsatisfiedlinkerror

Android NDK unsatisfiedLinkError (only on android <4.3)


I have found a lot of similar problems posted, but none of them seem to be exactly the same as this and none of the suggestions has worked.

I have written an Android app that uses the NDK and OpenCv for some image processing. All my algorithms are written in C++. I am using android studio, gradle 2.2.2 and the experimental gradle plugin 0.8.3.

When testing on an HTC M8, Galaxy S5 and LG V10 everything works flawlessly. But when trying to run on a Samsung Galaxy S2 or a Galaxy Ace3 the following error occures on launch:

java.lang.UnsatisfiedLinkError: Cannot load library: link_image[1892]: 1835 could not load needed library 'libopencv_java3.so for 'libnative.so' (load_library[1094]: Library 'libopencv_java3.so' not found)

In my MainActivity.java, i load the library:

static {
    System.loadLibrary("native")
}

and have my BaseLoaderCallback as follows:

private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
    @Override
    public void onManagerConnected(int status) {
        switch (status) {
            case LoaderCallbackInterface.SUCCESS: {
                Log.i(TAG, "OpenCV loaded successfully");
                mOpenCvCameraView.enableView();
            }
            break;
            default: {
                super.onManagerConnected(status);
            }
            break;
        }
    }
};

Additionally the OpenCv initialization in onCreate:

if (!OpenCVLoader.initDebug()) {
    Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
    OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, 
this, mLoaderCallback);
} else {
    Log.d(TAG, "OpenCV library found inside package. Using it!");
    mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
}

My build.gradle:

buildscript {
repositories {
    mavenCentral()
}
dependencies {
    classpath 'com.android.tools.build:gradle:2.2.2'
}
}

apply plugin: 'com.android.model.application'

model {
android {
    compileSdkVersion 23
    buildToolsVersion "23.0.3"

    defaultConfig.with {
        applicationId "com.me.myapp"
        minSdkVersion.apiLevel 15
        targetSdkVersion.apiLevel 23
        versionCode 9
        versionName "1.5.3"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    ndk {
        moduleName = "native"
        cppFlags.add("-I${file(getOpenCVDir())}".toString())
        cppFlags.add("-frtti")
        cppFlags.add("-fexceptions")
        ldLibs.addAll(["log", "opencv_java3"])
        stl = "gnustl_static"
    }
}
    buildTypes {
        release {

            //minifyEnabled false
            //proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    android.productFlavors {
        // for detailed abiFilter descriptions, refer to "Supported ABIs" @
        // https://developer.android.com/ndk/guides/abis.html#sa
        create("fat") {
            ndk.abiFilters.add("armeabi")
            ndk.abiFilters.add("armeabi-v7a")
            ndk.abiFilters.add("mips")
            ndk.abiFilters.add("x86")
            ndk.abiFilters.add("arm64_v8a")
            ndk.ldFlags.add("-L${file('src/main/jniLibs/armeabi')}".toString())
            ndk.ldFlags.add("-L${file('src/main/jniLibs/armeabi-v7a')}".toString())
            ndk.ldFlags.add("-L${file('src/main/jniLibs/mips')}".toString())
            ndk.ldFlags.add("-L${file('src/main/jniLibs/arm64_v8a')}".toString())
            ndk.ldFlags.add("-L${file('src/main/jniLibs/x86')}".toString())
        }
    }
}

def getOpenCVDir() {
    Properties properties = new Properties()
    properties.load(new File(rootDir.absolutePath + "/local.properties").newDataInputStream())
    def externalModuleDir = properties.getProperty('opencv.dir', null)
    if (externalModuleDir == null) {
        throw new GradleException(
            "OpenCV location not found. Define location with opencv.dir in the local.properties file!")
}
    return externalModuleDir
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
    exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:design:23.2.1'
testCompile 'junit:junit:4.12'
compile project(':openCVLibrary300')
compile 'com.google.android.gms:play-services-appindexing:9.0.0'
}

apply plugin: 'com.google.gms.google-services'

I also have the following folders with opencv libs in app/src/main/jniLibs:

arm64-v8a
armeabi
armeabi-v7a
mips
mips64
x64
x86_64

First I thought it was related to the ABI, but it seems both the M8 and the S2 are armeabi-v7a. I have also checked in the compiled apk's lib folder, each of the chosen abi folders is present and has the libopencv_java3.so and libnative.so files in it). Is there some incompatibility to lower android versions (<4.4) that I am not aware of?


Solution

  • In case anyone else is having this problem, this is what solved it for me:

    I changed the

    static {
        System.loadLibrary("native");
    }
    

    to

    static {
        if(!OpenCVLoader.initDebug())
             // Handle Error
        }else
        {
             System.loadLibrary("native");
        }
    }
    

    Additionally, I just added the call to mLoaderCallback.onManagerConnected to OnResume:

    public void onResume() {
        super.onResume();
        mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        .......
    }
    

    I have no idea why this works, so an explanation for this would still be appreciated. Otherwise, hope this helps someone