環境
Kotlin : 1.3.71
Android Native Development Kit (NDK) : 21.0.6113669
CMake : 3.10.2
LLBD : 3.1
コード
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
changeTextOf(button)
}
}
external fun changeTextOf(btn: Button): Unit
companion object {
init {
System.loadLibrary("native-lib")
}
}
}
extern "C" JNIEXPORT void JNICALL
Java_com_example_foo_MainActivity_changeTextOf(
JNIEnv* env,
jobject /* this */,
jobject btn) {
jclass clazz = env->FindClass("android/widget/Button");
jmethodID setText = env->GetMethodID(clazz, "setText", "(Ljava/lang/CharSequence;)V");
std::string str = "success!!!";
jstring arg = env->NewStringUTF(str.c_str());
env->CallVoidMethod(btn, setText, arg);
}
native-lib.cppの2行目について,パッケージの名前がcom.example.fooだったら,Java_com_example_foo_MainActivity_changeTextOfとなる.ここは自分のパッケージ名に合わせて修正.
以上のコードを実行すると,IDがbuttonのボタンをタップしたら,ボタンのテキストがsuccess!!!になる.以下,簡単にコードを説明.
FindClass()
android.widget.ButtonのsetText()を使いたいので,FindClassの引数には'.'を'/'に置き換えた"android/widget/Button"を渡す.
GetMethodID()
引数の1つ目はFindClassの戻り値,2つ目は使いたいメソッドの名前,3つ目は使いたいメソッドの引数.
3つ目の引数"(Ljava/lang/CharSequence;)V"は,"(引数)戻り値の型"となっている.Button.setText()は引数にCharSequenceをとり,値を返さない.なので,戻り値の型はVoidのVになっている.
詳しくは,JNIの型とデータ構造へ.
CallVoidMethod()
setText()には戻り値がない(Void)ので,setText()を呼び出すためにCallVoidMethod()を使う.Callの直後には使いたいJavaのメソッドの戻り値の型が来る.CallVoidMethod()の引数の1つ目は変更するボタンのオブジェクト(jobject),2つ目はGetMethodID()で取得したメソッドID,以降は使いたいメソッドの引数が来る.setText()はボタンに表示したい文字列を引数にとるので,これをCallVoidMethod()の引数の3つ目に渡す.
参考文献
JNI関数に様々な関数の説明がある.
Java Native Interfaceを使用する上でのベスト・プラクティスにも目を通しておきたい.