x86_64 studio r16b ndk google descargar android build android-ndk java-native-interface shared-libraries

studio - NDK de Android: crea dos bibliotecas nativas que se llaman una a la otra



ndk android studio (1)

El procedimiento de compilación correcto fue relativamente fácil, mi problema era que hacer que libmod1.so dependiera de libmod2.so causaba enlaces insatisfechos en el inicio: el código mod1 no podía encontrar la biblioteca compartida mod2, aunque ambos estaban presentes en la misma carpeta en la APK final. bajo libs / armeabi, libs / x86 etc. Sin embargo, para completar mi respuesta:

  • Coloque sus fuentes C o C ++ y sus archivos de encabezado en los subdirectorios de jni dir en su proyecto de Android, por ejemplo, las carpetas mod1 / y mod2 /

  • Según las instrucciones del NDK, cree el archivo Application.mk, por ejemplo, el mío es:

NDK_TOOLCHAIN_VERSION = 4.7
APP_PLATFORM: = android-8
APP_ABI: = armeabi armeabi-v7a x86

  • Crea Android.mk siguiendo esta plantilla:

LOCAL_PATH: = $ (call my-dir)
incluye $ (CLEAR_VARS)
LOCAL_SHARED_LIBRARIES: = mod2 # esto hace que libmod1.so sea dependiente de libmod2.so
LOCAL_MODULE: = mod1
LOCAL_SRC_FILES: = mod1 / file1.c
LOCAL_SRC_FILES + = mod1 / file2.cpp
...
incluir $ (BUILD_SHARED_LIBRARY) # esto en realidad construye libmod1.so

incluye $ (CLEAR_VARS)
LOCAL_MODULE: = mod2
LOCAL_SRC_FILES: = mod2 / file1.cc
LOCAL_SRC_FILES + = mod2 / file2.cc
...
incluye $ (BUILD_SHARED_LIBRARY) # esto genera libmod2.so

Eso es todo, todas las compilaciones sin quejas con el script ndkbuild. Solo necesitas un contenedor C para llamar a algunas funciones desde Java. Y aquí estaba mi problema. Como tenía funciones que se pueden llamar desde Java solo en libmod1.so, mi clase de contenedor de C en Java era como:

public class CWrapper { static { System.loadLibrary("mod1"); } public static native int func1(String aParam); ... }

Esto me pareció perfectamente lógico: llamé a libmod1.so desde Java, así que utilicé System.loadLibrary ("mod1"), y dado que libmod1.so sabe que depende de libmod2.so, y ambos archivos están en la misma carpeta, libmod1 sabrá cómo encontrar y cargar libmod2, ¿verdad? ¡Incorrecto! Se estrelló en el inicio de la aplicación con "enlace insatisfecho". El mensaje de error exacto fue:

java.lang.UnsatisfiedLinkError: Cannot load library: soinfo_link_image(linker.cpp:1635): could not load library "libmod2.so" needed by "libmod1.so"; caused by load_library(linker.cpp:745): library "libmod2.so" not found

Estaba buscando por todas partes un código más para agregar a Android.mk para resolver esto en vano. ¡Finalmente Eureka! He modificado mi clase CWrapper de la siguiente manera:

public class CWrapper { static { System.loadLibrary("mod2"); // must be first, as mod1 depends on mod2! System.loadLibrary("mod1"); } public static native int func1(String aParam); ... }

y las cosas empezaron a funcionar a la perfección ...

Greg

Perdió medio día intentando crear dos bibliotecas compartidas, por ejemplo, mod1 y mod2 (que Android NDK compila en libmod1.so y libmod2.so ), desde fuentes en una carpeta jni y subcarpetas, luego mod1 hace que una función llame desde mod2. Muchas respuestas sobre cómo hacer que la compilación funcionara, pero la vinculación dinámica en tiempo de ejecución no funcionaba, la aplicación se bloqueó al iniciarse.

Decidimos publicar esta pregunta y responderla de inmediato, de modo que las preguntas y respuestas de todo el proceso estén juntas y, con suerte, alguien más no pierda un día investigándolas nuevamente.