如何在Android Studio和NDK中使用额外的*.so库

8

我正在尝试生成一个 Android 应用程序,以使用一些额外的 *.so 库(具体来说是 'libinterface.so')。这些库是在外部生成的,并作为依赖项包含在从 Java 端调用的包装类中。该库存储在 'src/main/jniLibs/armeabi-v7a' 中。系统将所有 .so 文件都包含在生成的应用程序中。

之前,我使用 Eclipse 来实现此目的,并且能够使用此库,但我在使用 Android Studio 时遇到了问题。

生成的错误是:

/home/******/Libraries/android-sdk-linux/ndk-bundle/toolchains/aarch64-linux-android-4.9/prebuilt/linux-x86_64/bin/../lib/gcc/aarch64-linux-android/4.9/../../../../aarch64-linux-android/bin/ld: cannot find -linterface

由于错误是由链接器抛出的,看起来与库包含步骤有关。在Eclipse中,我使用了一个'Android.mk'文件来包含新库,但我无法找到使用Gradle实现这一点的方法。

#Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := libinterface-prebuilt
LOCAL_SRC_FILES := prebuilt/libinterface.so
include $(PREBUILT_SHARED_LIBRARY)

我正在尝试使用此 Gradle 定义包含库(注意:我已经按照这个教程中的最后 JNI 支持和 gradle-experimental):

...
android.buildTypes {
    release {
        minifyEnabled = false
        proguardFiles.add(file('proguard-android.txt'))
    }
}

android.ndk {
    moduleName = "custom_wrapper_jni"
    cppFlags.add("-I" + file("src/main/jni").absolutePath)
    cppFlags.add("-I" + file("../Integration/include").absolutePath)  // <- New library header include path 
    cppFlags.add("-L" + file("src/main/jniLibs/armeabi-v7a").absolutePath)  // <- Path where the library is stored
    cppFlags.add("-std=c++11")
    stl = "stlport_static" // Which STL library to use: gnustl or stlport
    ldLibs.add("log")

    ldLibs.add("interface")    //<- Library to be included
}
...

该库使用CMake和makefile工具进行外部编译,已经正确地交叉编译为Android平台(在Eclipse和ADT中进行了测试)。

我已经按照以下方式实现了包装器:

// custom_wrapper_jni.h
#ifndef ANDROID_JNI_H
#define ANDROID_JNI_H

#include <jni.h>

extern "C"
{
    JNIEXPORT jint JNICALL
    Java_com_example_goe_android_JniInterface_testFunction(JNIEnv *env,
                                                           jobject instance);
}
#endif

并且

// custom_wrapper_jni.cpp
#include <custom_wrapper_jni.h>

#include "Interface.h"   // Header of the included library

Interface* mInterface = Interface::create();  // Generate the library class instance

JNIEXPORT jint JNICALL
Java_com_example_goe_android_JniInterface_testFunction(JNIEnv *env,
                                                    jobject instance)
{
    LOGI("Test function called in wrapper!");
    return mInterface->test();    // Use the instance
}

图书馆的头部看起来像这样:

#ifndef INTERFACE_H__
#define INTERFACE_H__

#include <string>

class Interface
{
public:
    static Interface* create();
    virtual ~Interface(){}


    // Testing function
    virtual int test() = 0;

protected:
    Interface();
};
#endif // INTERFACE_H__

感谢您的提前帮助。

更新:

我根据这个例子,将一些块包含到gradle脚本中:

def lib_path = file("src/main/jniLibs").absolutePath

model {

    repositories {
        libs(PrebuiltLibraries) {
            newlibs {
                headers.srcDir file("../Integration/include").absolutePath
                binaries.withType(SharedLibraryBinary) {
                    sharedLibraryFile = file("${lib_path}/${targetPlatform.getName()}/libinterface.so")
                    println "Included libraries: " + file("${lib_path}/${targetPlatform.getName()}/libinterface.so")
                }
            }
        }
    }

    android {
     ...
    }

    android.sources {
        main {
            jni {
                dependencies {
                    library "newlibs" linkage "shared"
                }
            }
        }
    }
}

但是它没有起作用:
Error: org.gradle.nativeplatform.toolchain.internal.CommandLineToolInvocationFailure: Linker failed while linking libcustom_wrapper_jni.so.

你把libinterface.so放在哪里? - shhp
其他的.so库能够被正确加载吗? - shhp
我只是在使用这个库进行测试。我也可以使用其他库进行测试。有什么建议吗? - goe
也许你可以尝试一下其他的库是否可行。 - shhp
根据您的建议,我正在尝试加载OpenCV库。 - goe
显示剩余2条评论
1个回答

5

好的,可能存在两个不同的问题。

首先,您必须确保库已编译为正确的架构。如果您正在使用一个 armeabi-v7a 库,但编译器尝试加载一个 armeabi 库,则编译将失败。

其次,根据使用的架构包含库。 在您的模块 build.gradle 脚本中使用 'flavours' 配置。

例如,您可以尝试做这样的事情:

android.productFlavors {
    create("arm") {
        ndk.with{
            abiFilters.add("armeabi")

            File curDir = file('./')
            curDir = file(curDir.absolutePath)
            String libsDir = curDir.absolutePath + "/src/main/jniLibs/armeabi/"

            ldLibs.add(libsDir + "libinterface.so")
        }
    }
    create("armv7") {
        ndk.with {
            abiFilters.add("armeabi-v7a")

            File curDir = file('./')
            curDir = file(curDir.absolutePath)
            String libsDir = curDir.absolutePath + "/src/main/jniLibs/armeabi-v7a/"

            ldLibs.add(libsDir + "libinterface.so")
        }
    }
}

此外,我建议您使用“jniLibs”存储库,因为这是它们的默认路径,但对于每个架构,请使用不同的文件夹。
您可以查看其他示例,例如this
希望这有所帮助。问候。

如何使用这种方法编译fat库? - c4pQ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接