C++からJavaを呼び出しますぜ | Android系女史

Android系女史

Android開発など雑多なプログラムの愚痴でもしています。

eclipse上でc++コードをデバッグしたいという野望は現在中断。
このままだと進まないのでeclipse上でc++のコンパイルが出来たところで先に行くのです。

で、次はc++からJavaの関数の呼び出しです。

c++->Javaの呼び出しの基本はこんな感じ。

c++側
jclass jc = env->FindClass("com/java/package/ClassName");
if (jc == 0) {
  return false;
}

// メソッドの取得
jmethodID id = env->GetStaticMethodID(jc, "function", "()V");

//メソッドを実行。
env->CallStaticVoidMethod(jc, id);

java側
package com.java.package;

public class ClassName {
  public static void function() {
    // 何かする
  }
}

まずはFindClass関数でJavaクラスをゲット。
このときの"com/java/package"の部分は
パッケージ名でよい模様。
(詳しくは調べてない)

メソッドの取得はGetStaticMethodID。
Javaの関数がstaticじゃない場合はGetMethodIDとのこと。
第二引数が関数名。第三引数が引数と戻り値。
"()V"は引数なしのvoid型を返すという意味です。

で、実際にメソッドの呼び出しがCallStaticVoidMethod
Javaの関数がstaticじゃない場合は同じく"Static"の文字が不要。
そして返り値によって関数名が若干変わるらしい。
void型を返すからCallStaticVoidMethodだけど
これがint型を返すようなときはCallStaticIntMethodなんだとか。

このあたりは「Java/JNI - PukiWiki」がまとめられていて分かりやすかったです。
で、呼び出し方が分かったところでそもそもJNIEnv *envはどうやって取得しようという問題に当たります。

Java -> c -> JavaならJava->cで渡されたJNIEnvをそのまま利用すればよさそうですが
現在
Java -> c
OpenGLのコールバック -> c++ -> Java
なのでJNIEnvクラスを持ってないんです。
最初
Java -> cと呼び出されたときにJNIEnvクラスを保存しておこうかとも思ったのですが
JNIEnvは使いまわしができないようです。

じゃあどうすればいいんだと検索したら「【Android NDK】JNIEnv*の問題」が参考になりました。

要はJNIロード時に自動的に呼び出されるコールバック関数"jint JNI_OnLoad( JavaVM* vm, void* reserved )"の引数であるJavaVM*を保存しておいて
必要になったらこのJavaVMクラスのGetEnvメソッドを使用してJNIEnvを取得すればいいわけです。
これでようやくc++ -> Javaもできた。