Calling a Java Method from C++ in Android

Calling a java method from c++ in Android

If it's an object method, you need to pass the object to CallObjectMethod:

jobject result = env->CallObjectMethod(obj, messageMe, jstr);

What you were doing was the equivalent of jstr.messageMe().

Since your is a void method, you should call:

env->CallVoidMethod(obj, messageMe, jstr);

If you want to return a result, you need to change your JNI signature (the ()V means a method of void return type) and also the return type in your Java code.

Calling a Java function from the Native code using the NDK

Every C function that is callable from Java via JNI has a first parameter of type JNIEnv*. On the C end, this is a pointer to a pointer to a structure with a bunch of pointers to functions. Those functions are your interface to the Java world. FindClass, GetMethodID and the rest are among them.

So when you want to call FindClass from the C side, here's how you do it:

void Java_com_mypackage_MyClass_MyMethod(JNIEnv *jniEnv, jobject thiz)
{
jclass *clazz = (*(*jniEnv)->FindClass)(jniEnv, "com/mypackage/SomeClass");
jmethodID MethodID = (*(*jniEnv)->GetStaticMethodID)(jniEnv, clazz, "SomeMethod", "(I)I");
int result = (*(*jniEnv)->CallStaticIntMethod)(jniEnv, clazz, MethodID, 18);

And so forth. The line dereferences the jniEnv parameter, gets a function pointer and calls the function through it. Class and method names are completely bogus, naturally. How would I know yours.

Note: I'm talking of function pointers here, but not in the same sense as you do; those are function pointers to functions that JNI provides, not to your functions.

The verbosity of call syntax has to do with the limitations of C; in C++, you can write instead

jclass *cl = jniEnv->FindClass("com/mypackage/SomeClass");

as C++ supports function table pointers of this sort natively via virtual functions.

You can probably take some shortcuts along the way. If you're calling methods in the same class as your C point of entry, and it happens to be static, your second parameter already is a class object pointer. If you have a this pointer to the object you want to invoke a method on, you can use GetObjectClass.

Call Java function from C++ method

As an example, check Creating a JVM from C. It shows a sample procedure to create a JVM and invoke a method. If the JVM already exists; e.g. your C program is invoked by the Java program (callback situation), you can cache the JNIEnv* pointer.

As an advice, be careful caching pointers to the JVM from C/C++, there are some semantics involved as to what you can cache and it could be invoked later on.

Source: How to call Java functions from C++?

How to call java function and pass arguments from c++ using Android NDK

Symbol [ is used to represent arrays (as if you had String[] msg), remove that from your GetStaticMethodID method.

You can see more information about JNI Types and Data Structures here

Also as Michael said - you should check for java exceptions in your native code, because otherwise your app will crash. You can do it using Exception jni functions. For example:

jclass exClass = env->FindClass("some/random/class");
if (exClass == nullptr || env->ExceptionOccurred()) {
env->ExceptionClear();
// do smth in case of failure
}

How To Call JAVA Methods from inside of a Thread in JNI

I see two potential issues with the code:

1. Sharing a JNIEnv* across threads

Each native thread should obtain its own JNIEnv* by attaching itself to the JVM, and then detaching itself at some point. See this answer for more details and possible solutions.

2. Caching local references

The thiz reference you receive as the second argument to a native function is a local reference, as are most of the jobjects returned from calling JNI functions.

A local reference is usable only "from the thread it was originally handed to, and is valid until either an explicit call to DeleteLocalRef() or, more commonly, until you return from your native method".

If you want to use that object from another thread you need to create a global reference from the local reference:

m_globalObject = NewGlobalRef(thiz);

Remember to delete the global reference (DeleteGlobalRef(m_globalObject)) when you no longer need to use that object anywhere in your native code. Otherwise you may cause a memory leak.

Calling a Java function from C++ on Android over JNI

Instead of using FindClass, can you try using: (*env)->GetObjectClass(env, obj);



Related Topics



Leave a reply



Submit