Search code examples
androidgradleffmpegandroid-ndkjava-native-interface

Android Studio link prebuilt library .so error


I'm developing an Android app using FFmpeg. I have built FFmpeg into *.so files and put them into jniLibs as follows:

src

--main

----jniLibs

------armeabi

--------libavcodec-57.so

--------libavformat-57.so

--------xx.so

While in grade script, abifilter of ndk is armeabi.

In java files, I have succeeded load these .so files and the built apk also contains them. However, when I use any API (e.g. av_register_all()) of them in a .c file under src/jni folder, build error comes:

Error:(14) undefined reference to 'av_register_all'

Error:Execution failed for task ':app:compileDebugNdk'.

com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process 'command '/Users/zhouyf/Library/Android/sdk/ndk-bundle/ndk-build'' finished with non-zero exit value 2

It seems that problem exists in linker. But I found answer that just putting .so files to jniLibs/armeabi will be OK. Do I need modify build.gradle file to link those .so files or else?

P.S.

If I don't call the API, the app will run successfully, only with warning: W/linker: libavformat-57.so: unused DT entry: type 0x6ffffffe arg 0x60e0 W/linker: libavformat-57.so: unused DT entry: type 0x6fffffff arg 0x2

Environment: Android Studio 2.1.1 Mac OS X 10.11.5


Solution

  • You should add libraries as dependencies when you build by using ndk-build.

    Disable default ndk-build, in your build.gradle

    sourceSets.main {
        jniLibs.srcDir 'src/main/libs'
        jni.srcDirs = []
    }
    

    Add your own ndk-build task, in your build.gradle

    def ndkDir = properties.getProperty("ndk.dir")
    
    task ndkBuild(type: Exec) {
        if (Os.isFamily(Os.FAMILY_WINDOWS)) {
            commandLine ndkDir + File.separator + 'ndk-build.cmd', '-C', file('src/main/jni').absolutePath
        } else {
            commandLine ndkDir + File.separator + 'ndk-build', '-C', file('src/main/jni').absolutePath
        }
    }
    
    tasks.withType(JavaCompile) {
        compileTask -> compileTask.dependsOn ndkBuild
    }
    

    Finally, in your Android.mk, add the libraries like this.

    LOCAL_MODULE := # ...
    # ...
    LOCAL_LDFLAGS += -L/path/of/the/libraries -lavcodec-57 -lavformat-57 ...