Android NDK Import-Module / Code Reuse
-
28-10-2019 - |
質問
朝!
JNIを介してJavaとC ++の間のオブジェクトの動的なシリアル化を可能にする小さなNDKプロジェクトを作成しました。ロジックは次のように機能します:
bean-> javacinterface.java-> javacinterface.cpp-> javacinterface.java-> bean
問題は、他のプロジェクトでこの機能を使用したいことです。テストコードをプロジェクトから分離し、「テスター」プロジェクトを作成しました。テスタープロジェクトは、JavaオブジェクトをC ++に送信します。これは、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モジュールのヘッダーに依存するC ++ファイルは正常に動作します。また、JavaクラスはJnibridgeプロジェクトのインターフェイスを喜んで使用できます。リンクはすべて幸せです。
残念ながら、ネイティブメソッドコールを含むJavacInterface.javaは、静的ライブラリにあるJNIメソッドを確認できません。 (論理的には同じプロジェクトにありますが、両方ともプロジェクトにインポートされ、上記のメカニズムを介してそれらを使用したいと考えています)。
私の現在のソリューションは次のとおりです。誰かが私が達成しようとしていることのモジュール性の性質を維持する何かを提案できることを願っています:
私の現在の解決策は、javacinterface cppファイルを呼び出しプロジェクトに含めることです。
LOCAL_SRC_FILES := FunctionTable.cpp $(PATH_TO_SHARED_PROJECT)/JavaCInterface.cpp
しかし、Javacinterfaceアーキテクチャを変更した場合、プロジェクトに応じて各更新を必要とすることにつながるので、私はこれをしたくありません。
各ローカルプロジェクトでJNIメソッドシグネチャの新しいセットを作成することができ、インポートされたモジュールにリンクできます。繰り返しますが、これは実装を強く結合しすぎています。
解決
多くの血の汗と涙の後、私はこれを理解しました。
- Android JNIは、aからバイナリをロードします
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)