Android NDK: crea dos bibliotecas compartidas nativas que se llaman
Desperdiciado medio día tratando de construir dos bibliotecas compartidas, por ejemplo, mod1
y mod2
(que Android NDK compila libmod1.so
y libmod2.so
), de fuentes en una carpeta jni y subcarpetas, entonces mod1 llamar a una función de mod2. Un montón de respuestas sobre cómo hacer que el trabajo de construcción, pero luego el enlace dinámico de ejecución no estaba funcionando, la aplicación se estrelló en el arranque.
Decidió publicar esta pregunta y responderla inmediatamente, de modo que Q y A de todo el proceso estén juntos, y espero que alguien más no pierda un día investigándolo de nuevo.
- ¿Por qué algunos teléfonos Android hacen que nuestra aplicación lance un java.lang.UnsatisfiedLinkError?
- Cómo devolver array int de Java a JNI
- El proceso de alojamiento del servicio de cámara ha muerto inesperadamente
- No se puede asignar suficiente memoria en JNI
- ¿Es posible eliminar símbolos de una biblioteca compartida creada con Android NDK?
- Cómo imprimir los mensajes de registro con el marco de Android
- UnsatisfiedLinkError Android
- Android ICS 4.0 NDK NewStringUTF se está estrellando la aplicación
- Asignación simple que viene con valor incorrecto
- Macro de preprocesador en Android.mk se ignora, pero funciona en Application.mk
- No se encontró ninguna implementación para Native UnsatisfiedLinkError Exception Android JNI
- Android ndk (cmake): 'referencia indefinida a `__android_log_write' cuando se usa log api en la segunda biblioteca jni
- Android: 'No se pudo cargar Foo: findLibrary returned null'
El procedimiento de compilación correcto era relativamente fácil, mi problema era que hacer que libmod1.so dependiera de libmod2.so causaba enlaces insatisfechos al iniciar – el código mod1 no podía encontrar la biblioteca compartida mod2, aunque ambos estaban presentes dentro de la misma carpeta en el APK final, bajo libs / armeabi, libs / x86 etc. Sin embargo, para hacer mi respuesta completa:
-
Coloque sus fuentes de C o C ++ y los archivos de encabezado en subdirectorios de dir jni en su proyecto de Android, por ejemplo carpetas mod1 / y mod2 /
-
Por instrucciones de NDK, cree el archivo de Application.mk, eg 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: = $ (llame a my-dir)
incluya $ (CLEAR_VARS)
LOCAL_SHARED_LIBRARIES: = mod2 # esto hace que libmod1.so dependa de libmod2.so
LOCAL_MODULE: = mod1
LOCAL_SRC_FILES: = mod1 / file1.c
LOCAL_SRC_FILES + = mod1 / file2.cpp
…
incluya $ (BUILD_SHARED_LIBRARY) # esto construye realmente libmod1.soincluya $ (CLEAR_VARS)
LOCAL_MODULE: = mod2
LOCAL_SRC_FILES: = mod2 / file1.cc
LOCAL_SRC_FILES + = mod2 / file2.cc
…
incluyen $ (BUILD_SHARED_LIBRARY) # esto construye libmod2.so
Eso es todo, todas las compilaciones sin quejas con script ndkbuild. Sólo necesita un contenedor C para llamar a algunas funciones de Java. Y aquí estaba mi problema. Desde que tenía las funciones Callable de Java sólo en libmod1.so, mi clase C contenedor en Java era como:
public class CWrapper { static { System.loadLibrary("mod1"); } public static native int func1(String aParam); ... }
Esto me pareció perfectamente lógico: llamo a libmod1.so desde Java, así que utilicé System.loadLibrary ("mod1"), y puesto 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 estaba estrellando 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
Buscaba en todas partes un código más para agregar a Android.mk para resolver esto en vano. ¡Finalmente Eureka! Modifiqué 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 como un encanto …
Greg