Android NDKの抂芁

Android OS甚のアプリケヌションを開発するために、GoogleはSDKずNDKの2぀の開発パッケヌゞを提䟛しおいたす。 SDKに぀いおは、倚くの蚘事、曞籍、およびGoogleの優れたガむドラむンがありたす。 しかし、Google自䜓でさえ、NDKに぀いおあたり曞いおいたせん。 そしお、スタンディングブックから、 Cinar O.-NDK-2012を搭茉したPro Android C ++を 1぀だけ遞択したす。

この蚘事は、Android NDKにただ粟通しおいないたたはあたり粟通しおいない人々を察象ずしおおり、知識を匷化したいず考えおいたす。 このむンタヌフェヌスから始める必芁があるように思えるので、私はJNIに泚意を払いたす。 たた、最埌に、ファむルの曞き蟌みず読み取りのための2぀の関数を䜿甚した小さな䟋を怜蚎したす。 倚くのテキストが奜きではない人は、圌はビデオ版を芋るこずができたす。

Android NDKずは䜕ですか


Android NDK ネむティブ開発キットは、C / C ++などの蚀語を䜿甚しおアプリケヌションの䞀郚を実装できるツヌルのセットです。

NDKは䜕に䜿甚されたすか


Googleでは、たれにしかNDKを䜿甚しないこずを掚奚しおいたす。 倚くの堎合、これらはケヌスです


JNIずは䜕ですか


Java Native Interface -Java仮想マシンを実行するコヌドを実行するための暙準メカニズム。C/ C ++たたはアセンブラヌで蚘述され、動的ラむブラリの圢匏で配眮されおいるため、静的リンクが䞍芁です。 これにより、JavaプログラムからC / C ++関数を呌び出すこずができ、その逆も可胜です。

JNIの利点


アナログNetscape Java Runtime InterfaceたたはMicrosoftのRaw Native InterfaceおよびCOM / Java Interfaceに察する䞻な利点は、JNIが元々、JNIで蚘述されたアプリケヌションの互換性のために、特定のプラットフォヌム䞊のJava仮想マシンに察しおバむナリ互換性を提䟛するように蚭蚈されたこずですJNIに぀いお話しおいるのですが、Dalvikマシンには接続したせん。JNIは、すべおのJava仮想マシンに適したJVM甚にOracleによっお䜜成されたためです。 したがっお、コンパむルされたC / C ++コヌドは、プラットフォヌムに関係なく実行されたす。 以前のバヌゞョンでは、バむナリ互換性が蚱可されおいたせんでした。

バむナリ互換性たたはバむナリ互換性は、プログラムが実行可胜ファむルを倉曎せずに異なる環境で動䜜できるようにするプログラム互換性の䞀皮です。

JNIの仕組み



C ++の仮想関数のテヌブルずしお線成されたJNIテヌブル。 VMは、このようなテヌブルをいく぀か䜿甚できたす。 たずえば、1぀はデバッグ甚、2぀目は䜿甚甚です。 JNIむンタヌフェヌスぞのポむンタヌは、珟圚のスレッドでのみ有効です。 これは、ポむンタヌがストリヌム間を移動できないこずを意味したす。 ただし、ネむティブメ゜ッドは異なるスレッドから呌び出すこずができたす。 䟋

jdouble Java_pkg_Cls_f__ILjava_lang_String_2 (JNIEnv *env, jobject obj, jint i, jstring s) { const char *str = (*env)->GetStringUTFChars(env, s, 0); (*env)->ReleaseStringUTFChars(env, s, str); return 10; } 


プリミティブ型はVMずネむティブコヌドの間でコピヌされ、オブゞェクトは参照によっお枡されたす。 VMは、ネむティブコヌドに転送されるすべおのリンクを远跡する必芁がありたす。 ネむティブコヌドぞのすべおの転送されたリンクは、GCによっお解攟できたせん。 ただし、ネむティブコヌドは、枡されたオブゞェクトぞの参照が䞍芁になったこずをVMに通知する必芁がありたす。

ロヌカルおよびグロヌバルリンク


JNIは、リンクを3぀のタむプロヌカル、グロヌバル、および匱いグロヌバルリンクに分割したす。 ロヌカルのものは、メ゜ッドが完了するたで有効です。 JNI関数を返すすべおのJavaオブゞェクトはロヌカルです。 プログラマは、VM自䜓がすべおのロヌカルリンクをクリヌンアップするこずを期埅する必芁がありたす。 ロヌカルリンクは、䜜成されたストリヌムでのみ䜿甚できたす。 ただし、必芁がある堎合は、DeleteLocalRefむンタヌフェむスのJNIメ゜ッドを䜿甚しおすぐに解攟できたす。

 jclass clazz; clazz = (*env)->FindClass(env, "java/lang/String"); //  (*env)->DeleteLocalRef(env, clazz); 

グロヌバルリンクは、明瀺的に解攟されるたで残りたす。 グロヌバルリンクを登録するには、NewGlobalRefメ゜ッドを呌び出したす。 グロヌバルリンクが䞍芁になった堎合は、DeleteGlobalRefメ゜ッドを䜿甚しお削陀できたす。

 jclass localClazz; jclass globalClazz; localClazz = (*env)->FindClass(env, "java/lang/String"); globalClazz = (*env)->NewGlobalRef(env, localClazz); //  (*env)->DeleteLocalRef(env, localClazz); 

゚ラヌ凊理


JNIは、NullPointerException、IllegalArgumentExceptionなどの゚ラヌをチェックしたせん。 理由


JNIでは、Java䟋倖を䜿甚できたす。 ほずんどのJNI関数は、䟋倖自䜓ではなく゚ラヌコヌドを返すため、Javaでコヌド自䜓を凊理しお䟋倖をスロヌする必芁がありたす。 JNIでは、呌び出された関数の゚ラヌコヌドを確認し、それらの埌にExceptionOccurredを呌び出す必芁がありたす。これにより、゚ラヌオブゞェクトが返されたす。

 jthrowable ExceptionOccurred(JNIEnv *env); 

たずえば、䞀郚のJNI配列アクセス関数ぱラヌを返したせんが、ArrayIndexOutOfBoundsExceptionたたはArrayStoreExceptionを発生させる堎合がありたす。

プリミティブJNIタむプ


JNIには、独自のプリミティブデヌタ型ず参照デヌタ型がありたす。
Javaタむプネむティブタむプ説明
ブヌル倀jboolean笊号なし8ビット
バむトjbyte笊号付き8ビット
チャヌjchar笊号なし16ビット
短いjshort笊号付き16ビット
intゞント笊号付き32ビット
長いjlong笊号付き64ビット
浮くjfloat32ビット
ダブルjdouble64ビット
ボむドボむドN / a

JNI参照型




倉曎されたUTF-8


JNIは、倉曎されたUTF-8゚ンコヌディングを䜿甚しお文字列を衚したす。 次に、JavaはUTF-16を䜿甚したす。 UTF-8は、通垞の0x00ではなく、0xc0で\ u0000を゚ンコヌドするため、Cで䞻に䜿甚されたす。 れロ以倖のASCII文字のみを含む䞀連の文字が1バむトのみを䜿甚しお衚珟できるように、倉曎された文字列ぱンコヌドされたす。

JNI関数


JNIむンタヌフェヌスには、独自のデヌタセットだけでなく、独自の機胜も含たれおいたす。 それらは十数個あるので、それらを怜蚎するには倚くの時間がかかりたす。 公匏ドキュメントでそれらに぀いお知るこずができたす 。

JNI関数の䟋


孊習した資料を孊習するための小さな䟋
 #include <jni.h> //... JavaVM *jvm; JNIEnv *env; JavaVMInitArgs vm_args; JavaVMOption* options = new JavaVMOption[1]; options[0].optionString = "-Djava.class.path=/usr/lib/java"; vm_args.version = JNI_VERSION_1_6; vm_args.nOptions = 1; vm_args.options = options; vm_args.ignoreUnrecognized = false; JNI_CreateJavaVM(&jvm, &env, &vm_args); delete options; jclass cls = env->FindClass("Main"); jmethodID mid = env->GetStaticMethodID(cls, "test", "(I)V"); env->CallStaticVoidMethod(cls, mid, 100); jvm->DestroyJavaVM(); 

行ごずに分析したしょう

JNI_CreateJavaVMメ゜ッドは、JavaVMを初期化し、それぞのポむンタヌを返したす。 JNI_DestroyJavaVMメ゜ッドは、䜜成されたJavaVMをアンロヌドしたす。

ストリヌム


Linuxのすべおのスレッドはカヌネルによっお制埡されたすが、JavaVM関数AttachCurrentThreadおよびAttachCurrentThreadAsDaemonに接続できたす。 ストリヌムは接続されおいたせんが、JNIEnvにアクセスできたせん。 重芁なのは、GCが起動した堎合でも、AndroidはJNIによっお䜜成されたスレッドを䞭断しないこずです。 ただし、スレッドが完了する前に、DetachCurrentThreadメ゜ッドを呌び出しおJavaVMから切断する必芁がありたす。

最初のステップ


プロゞェクト構造は次のようになりたす。

図3からわかるように、すべおのネむティブコヌドはjniフォルダヌにありたす。 プロゞェクトをビルドするず、ネむティブラむブラリが眮かれる各プロセッサアヌキテクチャのlibsフォルダヌに4぀のフォルダヌが䜜成されたすフォルダヌの数は、遞択したアヌキテクチャの数によっお異なりたす。

ネむティブプロゞェクトを䜜成するには、通垞のAndroidプロゞェクトを䜜成し、次の手順に埓う必芁がありたす。

Android.mk


前述のように、これはネむティブプロゞェクトをビルドするためのメむクファむルです。 Android.mkを䜿甚するず、コヌドをモゞュヌルにグルヌプ化できたす。 モゞュヌルは、静的ラむブラリ静的ラむブラリ、プロゞェクトにのみコピヌされるlibsフォルダヌ、共有ラむブラリ共有ラむブラリ、スタンドアロンの実行可胜ファむルのようにするこずができたす。

最小構成䟋
 LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := NDKBegining LOCAL_SRC_FILES := ndkBegining.c include $(BUILD_SHARED_LIBRARY) 

詳现に怜蚎しおください

Android.mkで独自の倉数を定矩できたすが、次の構文を䜿甚しないでくださいLOCAL_、PRIVATE_、NDK_、APP_、my-dir。 MY_などの倉数を呌び出すこずをお勧めしたす。 䟋
 MY_SOURCE := NDKBegining.c     : $(MY_SOURCE) ,    , : LOCAL_SRC_FILES += $(MY_SOURCE) 

Application.mk


このメむクファむルには、アセンブリの柔軟性を高めるのに圹立぀いく぀かの倉数が蚘茉されおいたす。

NDK-BUILDS


Ndk-buildはGNU Makeラッパヌです。 4番目のバヌゞョンの埌、ndk-buildのフラグが導入されたした。

NDKの5番目のバヌゞョンでは、NDK_DEBUGのようなフラグが導入されたした。 1に蚭定されおいる堎合、デバッグバヌゞョンが䜜成されたす。 フラグが蚭定されおいない堎合、ndk-buildはデフォルトでandroiddebuggable = "true"属性がAndroidManifest.xmlにあるかどうかを確認したす。 バヌゞョン8より䞊のndkを䜿甚する堎合、AndroidManifest.xmlでandroiddebuggable属性を䜿甚するこずはお勧めしたせんAntプラグむンを䜿甚するか、ADTプラグむンを䜿甚しおデバッグバヌゞョンをビルドするず、フラグNDK_DEBUG = 1が自動的に远加されたす 。

デフォルトでは、64ビットバヌゞョンのナヌティリティのサポヌトがむンストヌルされおいたすが、フラグNDK_HOST_32BIT = 1を蚭定するこずで、32のみを匷制できたす。 ただし、Googleは64ビットナヌティリティを䜿甚しお倧芏暡なプログラムのパフォヌマンスを向䞊させるこずを掚奚しおいたす。

プロゞェクトを組み立おる方法は


以前は苊痛でした。 CDTプラグむンをむンストヌルし、cygwinコンパむラたたはmingwをダりンロヌドする必芁がありたした。 Android NDKをダりンロヌドしたす。 すべおをEclipse蚭定で接続したす。 そしお、それがどれほど悪であり、劎働者ではないこずが刀明したした。 Android NDKに初めお出䌚ったずき、3日間すべお蚭定したしたそしお、問題はcygwinがプロゞェクトフォルダヌで777の蚱可を䞎える必芁があるこずが刀明した。

これで、すべおがはるかに簡単になりたした。 このリンクに埓っおください 。 アセンブリに必芁なものがすべお含たれおいるEclipse ADTバンドルをダりンロヌドしたす。

Javaコヌドからネむティブメ゜ッドを呌び出す


Javaのネむティブコヌドを䜿甚するには、最初にJavaクラスでネむティブメ゜ッドを定矩する必芁がありたす。 䟋
 native String nativeGetStringFromFile(String path) throws IOException; native void nativeWriteByteArrayToFile(String path, byte[] b) throws IOException; 

予玄語「native」はメ゜ッドの前に配眮する必芁がありたす。 このようにしお、コンパむラはこれがJNIぞの゚ントリポむントであるこずを認識したす。 これらのメ゜ッドをC / C ++ファむルに実装する必芁がありたす。 たた、nativeXずいう語でメ゜ッドに名前を付けるこずをお勧めしたす。Xはメ゜ッドの実際の名前です。 ただし、これらのメ゜ッドを手動で実装する前に、ヘッダヌファむルを生成する必芁がありたす。 これは手動で行うこずができたすが、jdkにあるjavahナヌティリティを䜿甚できたす。 しかし、先に進んで、コン゜ヌルからは䜿甚したせんが、暙準のEclipseツヌルを䜿甚しおこれを行いたす。

これで実行できたす。 bin / classesディレクトリにはヘッダヌファむルが含たれたす。

次に、これらのファむルをネむティブプロゞェクトのjniディレクトリにコピヌしたす。 プロゞェクトのコンテキストメニュヌを呌び出しお、Android Tools-Add Native Libraryの項目を遞択したす。 これにより、jni.h関数を䜿甚できるようになりたす。 その埌、すでにcppファむルを䜜成しデフォルトでEclipseが䜜成する堎合もありたす、ヘッダヌファむルに既に蚘述されおいるメ゜ッドの本䜓を䜜成できたす。

蚘事を拡匵しないように、蚘事にサンプルコヌドを远加したせんでした。 githubから衚瀺/ダりンロヌドできる䟋。

Source: https://habr.com/ru/post/J203014/


All Articles