2011-06-15 12 views
12

¡Mañana!Android NDK import-module/reuse de código

He creado un pequeño proyecto NDK que permite la serialización dinámica de objetos entre Java y C++ a través de JNI. La lógica funciona así:

frijol -> JavaCInterface.Java -> JavaCInterface.cpp -> JavaCInterface.java -> Frijol

El problema es que quiero utilizar esta funcionalidad en otros proyectos. Separé el código de prueba del proyecto y creé un proyecto "Tester". El proyecto del probador envía un objeto Java a C++ que luego lo envía de vuelta a la capa de Java.

pensé que une sería bastante simple - ("simple" en términos de NDK/JNI es por lo general un día de frustración) añadí el proyecto JNIBridge como un proyecto de código y que incluye las siguientes líneas a Android.mk:

NDK_MODULE_PATH=.../JNIBridge/jni/"

JNIBridge/JNI/JavaCInterface/Android.mk:

... 
include $(BUILD_STATIC_LIBRARY) 

JNITester/JNI/Android.mk:

... 
include $(BUILD_SHARED_LIBRARY) 
$(call import-module, JavaCInterface) 

Todo esto funciona bien. Los archivos C++ que dependen de los encabezados del módulo JavaCInterface funcionan bien. Además, las clases de Java pueden usar interfaces del proyecto JNIBridge. Todos los enlaces están felices.

Desafortunadamente JavaCInterface.java que contiene las llamadas al método nativo no puede ver el método JNI ubicado en la biblioteca estática. (Lógicamente están en el mismo proyecto, pero ambos se importan al proyecto en el que desea utilizarlos a través del mecanismo anterior).

Mis soluciones actuales son las siguientes. Estoy esperando que alguien puede sugerir algo que va a preservar la naturaleza modular de lo que estoy tratando de lograr:


Mi solución actual sería incluir los archivos cpp JavaCInterface en el proyecto llamado así:

LOCAL_SRC_FILES := FunctionTable.cpp $(PATH_TO_SHARED_PROJECT)/JavaCInterface.cpp 

Pero prefiero no hacer esto ya que me llevaría a la necesidad de actualizar cada proyecto dependiente si cambio la arquitectura de JavaCInterface.


que podría crear un nuevo conjunto de firmas de los métodos JNI en cada proyecto local que luego enlazar a los módulos importados. Nuevamente, esto ata las implementaciones demasiado estrechamente.

Respuesta

14

Después de mucha sangre sudada y lágrimas He descubierto esto.

  • Android JNI carga su binario de SHARED_LIBRARY solamente.
  • JNI intentará vincular las llamadas nativas a las firmas/trozos de método apropiados de la Biblioteca compartida cargada (no buscará dentro de las bibliotecas compartidas vinculadas).
  • Puede crear una Biblioteca estática con estos métodos y compilarla en la Biblioteca compartida utilizada por su aplicación.

Usted puede construir su biblioteca estática en su proyecto original utilizando el siguiente código en su Andriod.xml:

include $(CLEAR_VARS) 
LOCAL_CFLAGS := -O0 
LOCAL_MODULE := LibraryToBeUsedInsideSharedLib 
LOCAL_SRC_FILES := ... 
include $(BUILD_STATIC_LIBRARY) // This builds a "Static Object" here: 
           // /Project/obj/local/armeabi/libLibraryToBeUsedInsideSharedLib.a 

include $(CLEAR_VARS) 
LOCAL_MODULE  := LibraryCalledFromJava 
LOCAL_SRC_FILES := ... 
LOCAL_STATIC_LIBRARIES := LibraryToBeUsedInsideSharedLib 
include $(BUILD_SHARED_LIBRARY) 

LOCAL_STATIC_LIBRARIES incluye la biblioteca estática en la biblioteca compartida. En su código de Java ahora se puede llamar a esto:

System.loadLibrary("LibraryCalledFromJava"); 

usted debería ser capaz de llamar a cualquiera de los métodos nativos ubicados dentro de la biblioteca LibraryToBeUsedInsideSharedLib desde cualquier punto de su código java.

Puede exportar el archivo libLibraryToBeUsedInsideSharedLib.a y utilizarlo en otros proyectos añadiendo esto a Android.xml del proyecto externo:

include $(CLEAR_VARS) 
LOCAL_MODULE   := LibraryToBeUsedInsideSharedLib 
LOCAL_LDLIBS   := -llog/ 
LOCAL_SRC_FILES   := $(MY_PREBUILT_LIB_DIR)/libLibraryToBeUsedInsideSharedLib.a 
include $(PREBUILT_STATIC_LIBRARY)