如何在 Android Studio 和 NDK 上使用额外的 *.so 库
How to use extra *.so libraries on Android Studio and NDK
我正在尝试生成一个 Android 应用程序以使用一些额外的 *.so 库(特别是 'libinterface.so')。这些库是在外部生成的,并作为依赖项包含在从 Java 端调用的包装器 class 中。该库存储在 '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 using this tutorial):
...
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工具进行外部编译,cross-compiled 'correctly' 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
}
图书馆的header是这样的:
#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__
提前致谢。
更新:
在 this example 之后,我在 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.
好的,可能有两个不同的问题。
首先,您必须确保库是为正确的体系结构编译的。如果您使用的是 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' 来存储库,因为它是它们的默认路径,但每个 arch 使用不同的文件夹。
您可以查看其他示例,例如 。
希望这对您有所帮助。你好。
我正在尝试生成一个 Android 应用程序以使用一些额外的 *.so 库(特别是 'libinterface.so')。这些库是在外部生成的,并作为依赖项包含在从 Java 端调用的包装器 class 中。该库存储在 '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 using this tutorial):
...
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工具进行外部编译,cross-compiled 'correctly' 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
}
图书馆的header是这样的:
#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__
提前致谢。
更新:
在 this example 之后,我在 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.
好的,可能有两个不同的问题。
首先,您必须确保库是为正确的体系结构编译的。如果您使用的是 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' 来存储库,因为它是它们的默认路径,但每个 arch 使用不同的文件夹。
您可以查看其他示例,例如
希望这对您有所帮助。你好。