Импорт-модуль NDK для Android/повторное использование кода
Утро!
Я создал небольшой проект NDK, который позволяет динамическую сериализацию объектов между Java и С++ через JNI. Логика работает следующим образом:
Bean → JavaCInterface.Java → JavaCInterface.cpp → JavaCInterface.java → Bean
Проблема заключается в том, что я хочу использовать эту функциональность в других проектах. Я отделил тестовый код от проекта и создал проект "Тестер". Проект тестера отправляет объект Java через С++, который затем возвращает его обратно на уровень Java.
Я думал, что связывание будет довольно простым - ( "Простой" с точки зрения NDK/JNI обычно является днем разочарования). Я добавил проект JNIBridge в качестве исходного проекта и включил следующие строки в 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)
Все это прекрасно работает. Файлы С++, которые полагаются на заголовки из модуля JavaCInterface, работают нормально. Также классы Java могут с радостью использовать интерфейсы из проекта JNIBridge. Все ссылки счастливы.
К сожалению, JavaCInterface.java, который содержит вызовы собственных методов, не может видеть метод JNI, расположенный в статической библиотеке. (Логически они находятся в одном проекте, но оба они импортируются в проект, где вы хотите использовать их через вышеупомянутый механизм).
Ниже перечислены мои текущие решения. Я надеюсь, что кто-то может предложить что-то, что сохранит модульную природу того, чего я пытаюсь достичь:
Моим текущим решением было бы включить файлы cpp JavaCInterface в вызывающем проекте так:
LOCAL_SRC_FILES := FunctionTable.cpp $(PATH_TO_SHARED_PROJECT)/JavaCInterface.cpp
Но я бы предпочел не делать этого, поскольку это привело бы к необходимости обновления каждого зависимого проекта, если бы я изменил архитектуру JavaCInterface.
Я мог бы создать новый набор сигнатур метода JNI в каждом локальном проекте, который затем ссылается на импортированные модули. Опять же, это слишком сильно связывает реализации.
Ответы
Ответ 1
После большого количества пота и слез крови я понял это.
- Android JNI загружает свой двоичный файл только с
SHARED_LIBRARY
.
- JNI попытается связать собственные вызовы с соответствующими сигнатурами/заглушками метода из загруженной общей библиотеки (она не будет входить в связанные общие библиотеки).
- Вы можете создать статическую библиотеку с помощью этих методов и создать ее в общей библиотеке, используемой вашим приложением.
Вы можете создать свою статическую библиотеку в своем исходном проекте, используя следующий код в вашем 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
включает статическую библиотеку в вашей общей библиотеке. В коде Java вы можете теперь вызвать это:
System.loadLibrary("LibraryCalledFromJava");
Вы должны иметь возможность вызывать любые встроенные методы, находящиеся внутри библиотеки LibraryToBeUsedInsideSharedLib
, из любой точки вашего java-кода.
Вы можете экспортировать файл libLibraryToBeUsedInsideSharedLib.a
и использовать его в других проектах, добавив его во внешний проект Android.xml:
include $(CLEAR_VARS)
LOCAL_MODULE := LibraryToBeUsedInsideSharedLib
LOCAL_LDLIBS := -llog/
LOCAL_SRC_FILES := $(MY_PREBUILT_LIB_DIR)/libLibraryToBeUsedInsideSharedLib.a
include $(PREBUILT_STATIC_LIBRARY)