Android NDK JNI soファイルの作成と使用
7075 ワード
なぜNDKを使うのですか?
要約すると、主に以下の状況に分けられます.
1.コードの保護は、apkのJava層コードが逆コンパイルされやすいため、C/C++ライブラリの逆コンパイルは難しい.
2.NDKでサードパーティC/C++ライブラリを呼び出します.ほとんどのオープンソースライブラリはC/C++コードで記述されているからです.
3.移植が容易で、C/C++で書かれたライブラリは他の組み込みプラットフォームで再利用するのに便利です.
一、NDK開発環境の構築:
環境変数PathにNDKのパス(D:Androidandroid-ndk-r 10 bなど)を追加すると、dosコマンドラインにndk-buildと入力すると次のプロンプトが表示されます.
Android NDK: Could not find application project directory ! Android NDK: Please define the NDK_PROJECT_PATH variable to point to it. /home/braincol/workspace/android/android-ndk-r5/build/core/build-local.mk:85: *** Android NDK: Aborting . Stop.
これはndk開発環境が構築に成功したことを示している.
二、コードの作成:
1.まずjavaコードを書く
AndroidアプリケーションエンジニアリングJniTestを構築し、パッケージcom.ext.jnitestでJniInvokeを作成 ファイル:
public class JniInvoke { /** * プログラムが実行を開始するとjni-invokeライブラリがロードされます(static領域で宣言されたコードは構築方法より先に実行されます) */ static { System.loadLibrary("jni-invoke"); } /** * nativeキーワード:このメソッドがローカルメソッドであることを示し、ローカルコード(C/C++)によって実現され、javaコードでは宣言のみである */ public native String getStringFromJNI();
public native void setStringToJNI(); }
2.対応するC/C++コードを作成し、mainディレクトリに入り、フォルダjniを新規作成する
2.1相応する.hファイルを生成して、.hファイルはただ私達が.cファイルを書くことを補助して、よく使った後に削除することができます
ローカルnativeメソッドに基づいてcのヘッダファイルを生成するには、端末modulesrcmainjava>javahクラスのフルパス(ファイル接尾辞を含まない)にアクセスする必要があります.
メソッドの署名を取得するにはmodule->build->intermediates->class->debug javap-sクラスのフルパスにアクセスする必要があります
http://www.cnblogs.com/zhuyp1015/p/4976116.html
#include /* Header for class com_ext_jnitest_JniInvoke */#ifndef _Included_com_ext_jnitest_JniInvoke #define _Included_com_ext_jnitest_JniInvoke #ifdef __cplusplus extern "C"{ #endif/* * Class: com_ext_jnitest_JniInvoke * Method: getStringFromJNI * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_ext_jnitest_JniInvoke_getStringFromJNI (JNIEnv *, jobject);/* * Class: com_ext_jnitest_JniInvoke * Method: setStringToJNI * Signature: ()Ljava/lang/String; */JNIEXPORT void JNICALL Java_com_ext_jnitest_JniInvoke_setStringToJNI (JNIEnv *, jobject); #ifdef __cplusplus } #endif#endif
注:上のコードのJNIEXPORTとJNICALLはjniのマクロであり、Androidのjniには不要であり、もちろん書いても間違いない.上のソースコードからC/C++ファイルに対応する関数名は特に長いが、その形式はJava_package_class_method、すなわちJava_パッケージ名_クラス名_メソッド名である.
文Signature:()Ljava/lang/String;
()関数を表すパラメータが空(ここでは空とは、JNIEnv*、jobjectの2つのパラメータ以外にパラメータはありません.JNIEnv*、jobjectはすべてのjni関数に必ずある2つのパラメータで、それぞれjni環境と対応するjavaクラス(またはオブジェクト)自体を表します.Ljava/lang/String;関数の戻り値がjavaのStringオブジェクトであることを示します
2.2該当する.cファイルを作成する:
#include #include /* * Class: com_ext_jnitest_JniInvoke * Method: getStringFromJNI * Signature: ()Ljava/lang/String; */jstring JNICALL Java_com_ext_jnitest_JniInvoke_getStringFromJNI (JNIEnv *env, jobject obj) { return (*env)->NewStringUTF(env, "get result from jni"); }/* * メソッド名:Java_パッケージ名_クラス名_メソッド名 * jni環境と対応するJavaクラス(またはオブジェクト)自体を表す2つのパラメータJNIEnv* * Class: com_ext_jnitest_JniInvoke * Method: setStringToJNI * Signature: ()Ljava/lang/String; */void JNICALL Java_com_ext_jnitest_JniInvoke_setStringToJNI (JNIEnv *env, jobject obj, jstring string){ char *str = (char *)(*env)->GetStringUTFChars(env, string, null); printf("%s"); (*env)->ReleaseStringURFChars(env, string, str); }
三.hello-jni.cをコンパイルして対応するライブラリを生成する
3.1 Android.mkファイルの作成:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jni-invoke
#GNU Make関数wildcardを使用して、「現在のプロジェクトパス/foo」ディレクトリの下にあるすべての「.c」ファイルを検索します.
MY_FILES := $(wildcard $(LOCAL_PATH)/*.c)
#見つかったすべてのファイル名の$(LOCLA_PATH)パスを削除し、/*.cのような名前しか残っていません.
MY_FILES := $(MY_FILES:$(LOCAL_PATH)/%=%)
LOCAL_SRC_FILES += $(MY_FILES)
#LOCAL_SRC_FILES := jni-invoke
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH:=$(call my-dir)Android.mkファイルは、まずLOCAL_PATH変数を定義する必要があります.開発ツリーでソースファイルを検索するために使用されます.この例では、マクロ関数'my-dir'は、現在のパス(Android.mkファイルを含むディレクトリ)を返すためにコンパイルシステムによって提供されます.
Include$(CLEAR_VARS)CLEAR_VARSはコンパイルシステムによって提供され、GNU MAKEFILEにLOCAL_PATH以外のLOCAL_XXX変数(例えばLOCAL_MODULE、LOCAL_SRC_FILES、LOCAL_STATIC_LIBRARIESなど)をクリアさせるように指定されています.これは、すべてのコンパイル制御ファイルが同じGNU MAKE実行環境にあるため、すべての変数がグローバルである必要です.
LOCAL_MODULE:=jni-invokeコンパイルのターゲットオブジェクト、LOCAL_MODULE変数は、Android.mkファイルに記述されている各モジュールを識別するために定義する必要があります.名前は一意で、スペースは含まれていない必要があります.注意:コンパイルシステムは、適切な接頭辞と接尾辞を自動的に生成します.すなわち、「hello-jni」と命名された共有ライブラリモジュールは、「libhello-j」を生成します.Ni.so'ファイル.
注意事項:ライブラリを「libhello-jni」と命名すると、コンパイルシステムはlib接頭辞を追加せず、Androidプラットフォームのソースコードに由来するAndroid.mkファイルをサポートするために「libhello-jni.so」も生成されます.もしあなたが本当にそうする必要があるなら.
LOCAL_SRC_FILES :=jni-invoke.c LOCAL_SRC_FILES変数には、モジュールにコンパイルするC/C++ソースファイルを含める必要があります.ここではヘッダファイルと含むファイルをリストする必要はありません.コンパイルシステムは、コンパイラに直接渡されるソースファイルだけを自動的に見つけるので、コンパイルシステムは依存するファイルをリストします.
なお、デフォルトのC++ソースファイルの拡張子は'.cpp'.です.異なる拡張子を指定することも可能です.LOCAL_DEFAULT_CPP_EXTENSION変数を定義すれば、「cxx'」ではなく「.cxx'」で始まる小さな点を忘れないでください.
include$(BUILD_SHARED_LIBRARY)BUILD_SHARED_LIBRARYはコンパイル生成共有ライブラリを表し、コンパイルシステムが提供する変数であり、GNU Makefileスクリプトを指し、前回呼び出した'include$(CLEAR_VARS)から収集を担当する'以降、LOCAL_XXX変数のすべての情報を定義し、何をコンパイルするか、どのように正しく行うかを決定している.また、BUILD_STATIC_LIBRARY変数は、静的ライブラリを生成することを示す:lib$(LOCAL_MODULE).a、BUILD_EXECUTTABLEは、実行可能ファイルを生成することを示す.
Android.mkの詳細については、以下を参照してください.http://www.2cto.com/kf/201310/253386.html
3.1 Application.mkファイルの作成:
APP_STL:=gnustl_static APP_CPPFLAGS:=-frtti-fexceptions APP_ABI:=armeabi-v 7 a#この文は生成されたcpu命令タイプを設定することである.ヒントとして、現在、ほとんどのアンドロイド携帯電話はarmeabiをサポートしているが、libsはタイプが多すぎて、apkパッケージにコンパイルすると大きすぎる
3.2コンソールウィンドウを開き、jniパスに入り、コマンドラインndk-buildを実行します.
必要な2つの設定
1.local.propertiesでNDKパスを設定します.私のNDKの例は次のとおりです.
sdk.dir=D\:\\Android\\sdk ndk.dir=D\:\\Android\\android-ndk-r11b
2.appのbuild.gradleのandroidノードで設定:
sourceSets {
main { jniLibs.src Dirs=['libs']//soファイルをappのlibsディレクトリの下に指定 } }
gradle.propertiesファイルに次の文を追加する必要がある場合もあります.
android.useDeprecatedNdk=true
ndk { moduleName "jni_invoke" //生成されたso名 ldLibs.addAll(['log']) //log出力関数__android_log_print、「LOCAL_LDLIBS:= -llog」はbuild.gradleファイルに次の構成を追加します. ldLibs.addAll(['log']) cppFlags.add("-std=c++11") cppFlags.add("-fexceptions") platformVersion 11 stl 'gnustl_shared' abiFilters「armeabi」、「armeabi-v 7 a」、「x 86」//出力指定の3種類のabiアーキテクチャの下のsoライブラリは、現在有無可能です.
}
app/build/intermediates/ndk/debug/libディレクトリの下に、構成で指定したプラットフォームのsoファイルが表示されます.
要約すると、主に以下の状況に分けられます.
1.コードの保護は、apkのJava層コードが逆コンパイルされやすいため、C/C++ライブラリの逆コンパイルは難しい.
2.NDKでサードパーティC/C++ライブラリを呼び出します.ほとんどのオープンソースライブラリはC/C++コードで記述されているからです.
3.移植が容易で、C/C++で書かれたライブラリは他の組み込みプラットフォームで再利用するのに便利です.
一、NDK開発環境の構築:
環境変数PathにNDKのパス(D:Androidandroid-ndk-r 10 bなど)を追加すると、dosコマンドラインにndk-buildと入力すると次のプロンプトが表示されます.
Android NDK: Could not find application project directory ! Android NDK: Please define the NDK_PROJECT_PATH variable to point to it. /home/braincol/workspace/android/android-ndk-r5/build/core/build-local.mk:85: *** Android NDK: Aborting . Stop.
これはndk開発環境が構築に成功したことを示している.
二、コードの作成:
1.まずjavaコードを書く
AndroidアプリケーションエンジニアリングJniTestを構築し、パッケージcom.ext.jnitestでJniInvokeを作成 ファイル:
public class JniInvoke { /** * プログラムが実行を開始するとjni-invokeライブラリがロードされます(static領域で宣言されたコードは構築方法より先に実行されます) */ static { System.loadLibrary("jni-invoke"); } /** * nativeキーワード:このメソッドがローカルメソッドであることを示し、ローカルコード(C/C++)によって実現され、javaコードでは宣言のみである */ public native String getStringFromJNI();
public native void setStringToJNI(); }
2.対応するC/C++コードを作成し、mainディレクトリに入り、フォルダjniを新規作成する
2.1相応する.hファイルを生成して、.hファイルはただ私達が.cファイルを書くことを補助して、よく使った後に削除することができます
ローカルnativeメソッドに基づいてcのヘッダファイルを生成するには、端末modulesrcmainjava>javahクラスのフルパス(ファイル接尾辞を含まない)にアクセスする必要があります.
メソッドの署名を取得するにはmodule->build->intermediates->class->debug javap-sクラスのフルパスにアクセスする必要があります
http://www.cnblogs.com/zhuyp1015/p/4976116.html
#include /* Header for class com_ext_jnitest_JniInvoke */#ifndef _Included_com_ext_jnitest_JniInvoke #define _Included_com_ext_jnitest_JniInvoke #ifdef __cplusplus extern "C"{ #endif/* * Class: com_ext_jnitest_JniInvoke * Method: getStringFromJNI * Signature: ()Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_com_ext_jnitest_JniInvoke_getStringFromJNI (JNIEnv *, jobject);/* * Class: com_ext_jnitest_JniInvoke * Method: setStringToJNI * Signature: ()Ljava/lang/String; */JNIEXPORT void JNICALL Java_com_ext_jnitest_JniInvoke_setStringToJNI (JNIEnv *, jobject); #ifdef __cplusplus } #endif#endif
注:上のコードのJNIEXPORTとJNICALLはjniのマクロであり、Androidのjniには不要であり、もちろん書いても間違いない.上のソースコードからC/C++ファイルに対応する関数名は特に長いが、その形式はJava_package_class_method、すなわちJava_パッケージ名_クラス名_メソッド名である.
文Signature:()Ljava/lang/String;
()関数を表すパラメータが空(ここでは空とは、JNIEnv*、jobjectの2つのパラメータ以外にパラメータはありません.JNIEnv*、jobjectはすべてのjni関数に必ずある2つのパラメータで、それぞれjni環境と対応するjavaクラス(またはオブジェクト)自体を表します.Ljava/lang/String;関数の戻り値がjavaのStringオブジェクトであることを示します
2.2該当する.cファイルを作成する:
#include #include /* * Class: com_ext_jnitest_JniInvoke * Method: getStringFromJNI * Signature: ()Ljava/lang/String; */jstring JNICALL Java_com_ext_jnitest_JniInvoke_getStringFromJNI (JNIEnv *env, jobject obj) { return (*env)->NewStringUTF(env, "get result from jni"); }/* * メソッド名:Java_パッケージ名_クラス名_メソッド名 * jni環境と対応するJavaクラス(またはオブジェクト)自体を表す2つのパラメータJNIEnv* * Class: com_ext_jnitest_JniInvoke * Method: setStringToJNI * Signature: ()Ljava/lang/String; */void JNICALL Java_com_ext_jnitest_JniInvoke_setStringToJNI (JNIEnv *env, jobject obj, jstring string){ char *str = (char *)(*env)->GetStringUTFChars(env, string, null); printf("%s"); (*env)->ReleaseStringURFChars(env, string, str); }
三.hello-jni.cをコンパイルして対応するライブラリを生成する
so
3.1 Android.mkファイルの作成:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := jni-invoke
#GNU Make関数wildcardを使用して、「現在のプロジェクトパス/foo」ディレクトリの下にあるすべての「.c」ファイルを検索します.
MY_FILES := $(wildcard $(LOCAL_PATH)/*.c)
#見つかったすべてのファイル名の$(LOCLA_PATH)パスを削除し、/*.cのような名前しか残っていません.
MY_FILES := $(MY_FILES:$(LOCAL_PATH)/%=%)
LOCAL_SRC_FILES += $(MY_FILES)
#LOCAL_SRC_FILES := jni-invoke
include $(BUILD_SHARED_LIBRARY)
LOCAL_PATH:=$(call my-dir)Android.mkファイルは、まずLOCAL_PATH変数を定義する必要があります.開発ツリーでソースファイルを検索するために使用されます.この例では、マクロ関数'my-dir'は、現在のパス(Android.mkファイルを含むディレクトリ)を返すためにコンパイルシステムによって提供されます.
Include$(CLEAR_VARS)CLEAR_VARSはコンパイルシステムによって提供され、GNU MAKEFILEにLOCAL_PATH以外のLOCAL_XXX変数(例えばLOCAL_MODULE、LOCAL_SRC_FILES、LOCAL_STATIC_LIBRARIESなど)をクリアさせるように指定されています.これは、すべてのコンパイル制御ファイルが同じGNU MAKE実行環境にあるため、すべての変数がグローバルである必要です.
LOCAL_MODULE:=jni-invokeコンパイルのターゲットオブジェクト、LOCAL_MODULE変数は、Android.mkファイルに記述されている各モジュールを識別するために定義する必要があります.名前は一意で、スペースは含まれていない必要があります.注意:コンパイルシステムは、適切な接頭辞と接尾辞を自動的に生成します.すなわち、「hello-jni」と命名された共有ライブラリモジュールは、「libhello-j」を生成します.Ni.so'ファイル.
注意事項:ライブラリを「libhello-jni」と命名すると、コンパイルシステムはlib接頭辞を追加せず、Androidプラットフォームのソースコードに由来するAndroid.mkファイルをサポートするために「libhello-jni.so」も生成されます.もしあなたが本当にそうする必要があるなら.
LOCAL_SRC_FILES :=jni-invoke.c LOCAL_SRC_FILES変数には、モジュールにコンパイルするC/C++ソースファイルを含める必要があります.ここではヘッダファイルと含むファイルをリストする必要はありません.コンパイルシステムは、コンパイラに直接渡されるソースファイルだけを自動的に見つけるので、コンパイルシステムは依存するファイルをリストします.
なお、デフォルトのC++ソースファイルの拡張子は'.cpp'.です.異なる拡張子を指定することも可能です.LOCAL_DEFAULT_CPP_EXTENSION変数を定義すれば、「cxx'」ではなく「.cxx'」で始まる小さな点を忘れないでください.
include$(BUILD_SHARED_LIBRARY)BUILD_SHARED_LIBRARYはコンパイル生成共有ライブラリを表し、コンパイルシステムが提供する変数であり、GNU Makefileスクリプトを指し、前回呼び出した'include$(CLEAR_VARS)から収集を担当する'以降、LOCAL_XXX変数のすべての情報を定義し、何をコンパイルするか、どのように正しく行うかを決定している.また、BUILD_STATIC_LIBRARY変数は、静的ライブラリを生成することを示す:lib$(LOCAL_MODULE).a、BUILD_EXECUTTABLEは、実行可能ファイルを生成することを示す.
Android.mkの詳細については、以下を参照してください.http://www.2cto.com/kf/201310/253386.html
3.1 Application.mkファイルの作成:
APP_STL:=gnustl_static APP_CPPFLAGS:=-frtti-fexceptions APP_ABI:=armeabi-v 7 a#この文は生成されたcpu命令タイプを設定することである.ヒントとして、現在、ほとんどのアンドロイド携帯電話はarmeabiをサポートしているが、libsはタイプが多すぎて、apkパッケージにコンパイルすると大きすぎる
3.2コンソールウィンドウを開き、jniパスに入り、コマンドラインndk-buildを実行します.
必要な2つの設定
1.local.propertiesでNDKパスを設定します.私のNDKの例は次のとおりです.
sdk.dir=D\:\\Android\\sdk ndk.dir=D\:\\Android\\android-ndk-r11b
2.appのbuild.gradleのandroidノードで設定:
sourceSets {
main { jniLibs.src Dirs=['libs']//soファイルをappのlibsディレクトリの下に指定 } }
gradle.propertiesファイルに次の文を追加する必要がある場合もあります.
android.useDeprecatedNdk=true
so
app build.gradle android defaultConfig :
ndk { moduleName "jni_invoke" //生成されたso名 ldLibs.addAll(['log']) //log出力関数__android_log_print、「LOCAL_LDLIBS:= -llog」はbuild.gradleファイルに次の構成を追加します. ldLibs.addAll(['log']) cppFlags.add("-std=c++11") cppFlags.add("-fexceptions") platformVersion 11 stl 'gnustl_shared' abiFilters「armeabi」、「armeabi-v 7 a」、「x 86」//出力指定の3種類のabiアーキテクチャの下のsoライブラリは、現在有無可能です.
}
app/build/intermediates/ndk/debug/libディレクトリの下に、構成で指定したプラットフォームのsoファイルが表示されます.