Подтвердить что ты не робот

Импорт-модуль 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 в каждом локальном проекте, который затем ссылается на импортированные модули. Опять же, это слишком сильно связывает реализации.

4b9b3361

Ответ 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)