Android JNIのJavaとCが呼び出し合う
概要
JNIって何?
JNIはJava Native Interfaceの略で、いくつかのAPIを提供してJavaと他の言語の通信(主にC&C++)を実現しています.Java 1.1からJNI標準はjavaプラットフォームの一部となり、Javaコードと他の言語で書かれたコードとのインタラクションを可能にします.
NDKって何?
NDKはNative Development Kitの略です.SDK(ソフトウェア開発キット)ソフトウェア開発キットの一部ですが、通常は単独でダウンロードする必要があります.詳細はNDKについて.
JNIのメリットとデメリットの利点: は他の言語と対話し、それぞれ長所を取っている. 反コンパイル難易度 を増加
欠点: Javaクロスプラットフォームの優位性を失う
Java呼び出しC配置 . を使用コマンド
は最後に「I come from C」に戻る.
は、
C Java呼び出し は、
JNIって何?
JNIはJava Native Interfaceの略で、いくつかのAPIを提供してJavaと他の言語の通信(主にC&C++)を実現しています.Java 1.1からJNI標準はjavaプラットフォームの一部となり、Javaコードと他の言語で書かれたコードとのインタラクションを可能にします.
NDKって何?
NDKはNative Development Kitの略です.SDK(ソフトウェア開発キット)ソフトウェア開発キットの一部ですが、通常は単独でダウンロードする必要があります.詳細はNDKについて.
JNIのメリットとデメリット
Java呼び出しC
module
下のbuild.gradle
android {
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
...
ndk {
moduleName "CallEachOther" // so , loadLibrary
abiFilters "armeabi","armeabi-v7a","x86","x86_64","mips","arm64-v8a","mips64"//
}
}
}
Java
クラスpublic class JNITest_Java {
static {
System.loadLibrary("CallEachOther");
}
public native String getStringFromC();
}
ここでSystem.loadLibrary
のパラメータはbuild.gradle
のmoduleName
の値、すなわちCallEachOther
である.ここではnative
法getStringFromC()
を定義した.これまで、Java
端は一時的に一段落した.次に、ヘッダファイルを生成します..h
ヘッダファイルを生成AS
に付属のTerminal
cd src/main/java
コマンドを開いてJava
フォルダの下に入ります.ps:cmd
コマンドと同様の効果javah .
を入力します.たとえば、javah com.dongyk.jnitest.JNITest_Java。
は、Java
ディレクトリの下で _ .h
を生成します.AS2.2.2
が開くと赤くなり、AS
のbug
のようです.ただし、通常のコンパイルには影響しません.main
ディレクトリの下にjni
フォルダを新規作成し、JniTestC.c
を新規作成します.
#include
#include
#include "com_dongyk_jnitest_JNITest_Java.h"
JNIEXPORT jstring JNICALL Java_com_dongyk_jnitest_JNITest_1Java_getStringFromC(JNIEnv * env, jobject jobj){
char* str = "I come from C";
return (*env)->NewStringUTF(env,str);
};
ここの方法の名前には一定のルールがあります.フォーマット:Java_ _
.メソッド名が長すぎる場合は、生成したばかりの.h
ファイルからコピーすることをお勧めします.この方法を簡単に説明します.JNIEnv * env
env
ポインタは、関数ポインタテーブルを指します.jobject jobj
は、Java
コードでインスタンス化されたJava
オブジェクトを指し、thisポインタに相当する.(*env)->NewStringUTF
は、env#NewStringUTF()
メソッドを呼び出すことを表す.MainActivity
で呼び出される.public class MainActivity extends AppCompatActivity {
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
String result = new JNITest_Java().getStringFromC();
tv.setText(result);
}
}
C Java呼び出し
Java
クラスにメソッドpublic class JNITest_Java {
static {
System.loadLibrary("JavaCallC");
}
public native String getStringFromC();
public native int callAdd();
public int add(int a, int b) {
Log.i("TAG","add was called");
return a + b;
}
}
を追加して、まず流れを理解します.Java
階層で呼び出されたのはJava
コードに違いありません.ここにはcallAdd()
メソッドが書かれています.このメソッドを呼び出すとき、C
にadd()
メソッドを呼び出すように通知します.このプロセスでは、C
がJava
メソッドの具体的な実装として最初に実行され、C
でJava
メソッドが呼び出される.その後、javah
コマンドが呼び出され、.h
ヘッダファイルが生成される./* DO NOT EDIT THIS FILE - it is machine generated */
#include
/* Header for class com_dongyk_jnitest_JNITest_Java */
#ifndef _Included_com_dongyk_jnitest_JNITest_Java
#define _Included_com_dongyk_jnitest_JNITest_Java
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_dongyk_jnitest_JNITest_Java
* Method: getStringFromC
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL ava_com_dongyk_jnitest_JNITest_1Java_getStringFromC
(JNIEnv
*, jobject);
/*
* Class: com_dongyk_jnitest_JNITest_Java
* Method: callAdd
* Signature: ()V
*/
JNIEXPORT jint JNICALL Java_com_dongyk_jnitest_JNITest_1Java_callAdd
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
.c
主関数の具体的な実装JNIEXPORT jint JNICALL Java_com_dongyk_jnitest_JNITest_1Java_callAdd(JNIEnv *env, jobject jobj){
//
jclass clazz = (*env)->FindClass(env,"com/dongyk/jnitest/JNITest_Java");
//
jmethodID jmethodid = (*env)->GetMethodID(env,clazz,"add","(II)I");
//
jobject jobject = (*env)->AllocObject(env,clazz);
//
return (*env)->CallIntMethod(env,jobject,jmethodid,3,5);
};
(*env)->GetMethodID
の最後のパラメータは、方法署名である.Java
はメソッドのリロードをサポートするが、これらのリロードのメソッドはJni
で同じ名前で命名され、関数のリロードを区別するためにメソッド署名が導入される.メソッド署名の取得:まずrebulid
で工事を行い、その後cd build\intermediates\classes\debug
で、その後javap -s /
ですべてのメソッド署名を取得します.例えば、javap -s com/dongyk/jnitest/JNITest_Java
public int add(int, int);
descriptor: (II)I
descriptor
に対応するのがメソッド署名である.もちろんです.中にはFindClass、GetMethodID
などの方法もあります.詳しくはXXXsdkdk-bundleplatformsandroid-xxarch-armusrincludejni.hを参照してください.MainActivity
で呼び出される.public class MainActivity extends AppCompatActivity {
private TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.tv);
int result = new JNITest_Java().callAdd();
tv.setText(result+"");
}
}
これで、Jni
初入門の小Demo
の作成が完了~