Cómo utilizar bibliotecas extra * .so en Android Studio y NDK
Estoy intentando generar una aplicación de Android para usar algunas bibliotecas extra * .so (específicamente 'libinterface.so'). Esas bibliotecas se generan externamente y se incluyen como una dependencia dentro de una clase de contenedor llamada desde Java. La biblioteca se almacena en 'src / main / jniLibs / armeabi-v7a'. El sistema incluye todo el archivo .so en la aplicación generada.
Anteriormente, estaba usando Eclipse para este propósito y pude usar esta biblioteca, pero tengo problemas para hacer esto con Android Studio.
- JNI operaciones de mapa de bits, para ayudar a evitar OOM cuando se utilizan imágenes grandes
- ¿Cuáles son las consecuencias si intentamos conectar un hilo nativo permanentemente a la DVM (JVM)?
- Error de libcurl CURLE_SSL_CACERT_BADFILE en android
- ¿Android realmente no tiene wchar_t?
- Extraer código de archivo .aar Android
El error generado es:
/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
Como el error es lanzado por el vinculador, parece relacionado con el paso de inclusión de biblioteca. En Eclipse, estaba usando un archivo 'Android.mk' para incluir la nueva biblioteca, pero no puedo encontrar la manera de hacerlo usando 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)
Estoy tratando de incluir las bibliotecas con esta definición gradle (Nota: He incluido el último soporte de JNI y gradle-experimental usando este 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 } ...
La biblioteca se compila externamente con las herramientas de CMake y makefile, y se compila de forma cruzada "correctamente" para la plataforma Android (probada con Eclipse y ADT).
He implementado la envoltura de esta manera:
// 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
y
// 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 }
El encabezado de la biblioteca se ve así:
#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__
Gracias por adelantado.
ACTUALIZAR:
Siguiendo este ejemplo , he incluido algunos bloques en el script 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" } } } } }
Pero no funciona:
Error: org.gradle.nativeplatform.toolchain.internal.CommandLineToolInvocationFailure: Linker failed while linking libcustom_wrapper_jni.so.
- ¿Cómo puedo depurar eficazmente el código C que está envuelto con JNI en Eclipse? (Android Dev)
- La aplicación de Android NDK no puede acceder a ningún punto de interrupción
- Desbordamiento de ReferenceTable (máx = 512) JNI
- Env-> FindClass función devuelve null
- Llame a un método java estático de otro paquete de código nativo
- Comportamiento sorpresa de eclipse para archivos C mientras se utiliza JNI, ¿Por qué?
- Manejo de excepciones de Android JNI
- No se puede obtener el valor JNIEnv * en contexto arbitrario
Ok, podría haber dos problemas diferentes.
En primer lugar, debe asegurarse de que la biblioteca está compilada para la arquitectura correcta. Si está utilizando una biblioteca armeabi-v7a, pero el compilador está intentando cargar una biblioteca armeabi, la compilación fallará.
En segundo lugar, y siguiendo también con la primera edición, usted tiene que incluir las bibliotecas que dependen de la arquitectura usada. Utilice la configuración de ' sabores ' en su script build.gradle de módulo.
En el ejemplo, puede intentar hacer algo como esto:
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") } } }
Además, le sugiero que utilice 'jniLibs' para almacenar las librerías, ya que es la ruta predeterminada para ellas, pero utilice una carpeta diferente para cada arco.
Puedes consultar otros ejemplos como este .
Espero que esto ayude. Saludos.