Domanda

Mattina!

Ho creato un piccolo progetto NDK che consente una serializzazione dinamica degli oggetti tra Java e C ++ tramite JNI. La logica funziona in questo modo:

Bean -> javacinterface.java -> javacinterface.cpp -> javacinterface.java -> bean

Il problema è che voglio utilizzare questa funzionalità in altri progetti. Ho separato il codice di prova dal progetto e ho creato un progetto "tester". Il progetto Tester invia un oggetto Java a C ++ che poi riecheggia nel livello Java.

Ho pensato che il collegamento sarebbe stato piuttosto semplice - ("semplice" in termini di NDK/JNI è di solito un giorno di frustrazione) ho aggiunto il progetto Jnibridge come progetto di origine e includendo le seguenti righe su 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)

Tutto funziona bene. I file C ++ che si basano sulle intestazioni del modulo Javacinterface funzionano bene. Anche le classi Java possono usare felicemente le interfacce del progetto Jnibridge. Tutto il collegamento è felice.

Sfortunatamente javacinterface.java che contiene le chiamate del metodo nativo non può vedere il metodo JNI situato nella libreria statica. (Logicamente sono nello stesso progetto ma entrambi vengono importati nel progetto in cui si desidera usarli attraverso il meccanismo di cui sopra).

Le mie soluzioni attuali sono seguenti. Spero che qualcuno possa suggerire qualcosa che preserverà la natura modulare di ciò che sto cercando di ottenere:


La mia soluzione attuale sarebbe quella di includere i file CPP Javacinterface nel progetto di chiamata in questo modo:

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

Ma preferirei non farlo perché mi porterebbe a dover aggiornare ogni progetto a seconda se cambiassi l'architettura Javacinterface.


Potrei creare un nuovo set di firme del metodo JNI in ciascun progetto locale che quindi si collega ai moduli importati. Ancora una volta, questo lega le implementazioni troppo strettamente.

È stato utile?

Soluzione

Dopo molto sudore e lacrime di sangue l'ho capito.

  • Android JNI carica il suo binario da a SHARED_LIBRARY solo.
  • JNI proverà a collegare le chiamate native alle firme/stub del metodo appropriato dalla libreria condivisa caricata (non sembrerà all'interno delle librerie condivise collegate).
  • È possibile creare una libreria statica con questi metodi e costruirla nella libreria condivisa utilizzata dall'applicazione.

Puoi creare la tua libreria statica nel tuo progetto originale utilizzando il seguente codice nel tuo 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 Include la libreria statica nella libreria condivisa. Nel tuo codice Java ora puoi chiamare questo:

System.loadLibrary("LibraryCalledFromJava");

Dovresti essere in grado di chiamare qualsiasi metodo nativo situato all'interno del LibraryToBeUsedInsideSharedLib Libreria da qualsiasi punto del tuo codice Java.

Puoi esportare il libLibraryToBeUsedInsideSharedLib.a archivialo e usalo in altri progetti aggiungendo questo al progetto esterno Android.xml:

include $(CLEAR_VARS)
LOCAL_MODULE            := LibraryToBeUsedInsideSharedLib
LOCAL_LDLIBS            := -llog/
LOCAL_SRC_FILES         := $(MY_PREBUILT_LIB_DIR)/libLibraryToBeUsedInsideSharedLib.a
include $(PREBUILT_STATIC_LIBRARY)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top