Call Java method from C++

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Post Reply
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Call Java method from C++

Post by LunaRebirth »

Hey guys,

I know how to use the JNI to call a java method in C++, but I'm having troubles getting the program to find the class.

Here's my code:

Code: Select all

JNIEnv* env = 0;
app->activity->vm->AttachCurrentThread(&env, NULL);
jclass myClass = env->FindClass("com/Game/app/Game");
if (myClass == 0) {
   return;
}
Game::log("OK.\n");
jmethodID mid = env->GetMethodID(myClass, "getOpenFileName", "()V"); // porting "getOpenFileName" to Android
if (mid == 0)
   Game::log("COULDN'T FIND METHOD.\n");
jstring hundred = (jstring)env->CallObjectMethod(myClass, mid);
app->activity->vm->DetachCurrentThread();
I can see that "com/Game/app/Game" exists in my output directory as com > Game > app > Game.class

If I look for a different class, I.E

Code: Select all

jclass myClass = env->FindClass("java/io/File");
it can find the class, no issues.

The exact error I receive is

Code: Select all

01-05 01:13:12.937  8976  8976 F DEBUG   : Abort message: 'thread.cc:2090] No pending exception expected: java.lang.ClassNotFoundException: Didn't find class "com.Game.app.Game" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib, /system/lib]]'
I find the DexPathList a little suspicious that it doesn't contain the any local files, but I'm sure the directory "." makes up for that, so likely that's not an issue.

Finally, here is my Java code:

Code: Select all

package com.Game.app;
 
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
 
import android.view.WindowManager;
import android.view.View;
import android.net.Uri;
 
public class Game extends android.app.NativeActivity {
 
    // other methods that aren't relevant to this question
 
     public void getOpenFileName()
     {
           Intent intent = new Intent().setType("*/*").setAction(Intent.ACTION_GET_CONTENT);
           startActivityForResult(Intent.createChooser(intent, "Select a file"), 123);
     }
}
I cannot find what I'm doing wrong.
Suggestions would be appreciated.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Call Java method from C++

Post by CuteAlien »

Uh, too long ago - don't remember. But looking at my code I seem to get all my own classes from my own NativeActivity class
(something like public class MyNativeActivity extends android.app.NativeActivity).

So it looks like:

Code: Select all

 
// Get function to get the class  I want. For this to work my NativeActivity has a function:
// public BillingHelper getBillingHelper()
jobject objectActivity = mAndroidApp.activity->clazz;
jclass classActivity = jniEnv->GetObjectClass(objectActivity);
jmethodID methodGetInAppHelper = jniEnv->GetMethodID(classActivity, "getBillingHelper", "()Lcom/irrgheist/hcraft_championship/BillingHelper;");
 
// now call that function to get the class object
jobject objectInAppHelper = jniEnv->CallObjectMethod(objectActivity, methodGetInAppHelper);
jclass classInAppHelper = jniEnv->GetObjectClass(objectInAppHelper);
 
// now can call the method for my own class
jmethodID methodRequestSynchronize = jniEnv->GetMethodID(classInAppHelper, "requestServerConnection", "()V");
jniEnv->CallVoidMethod(objectInAppHelper, methodRequestSynchronize);
 
mAndroidApp is an "android_app" object. And real code has checks after each call (it's in billing_googleplay.cpp in hcraft code if you want to see original code).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Call Java method from C++

Post by LunaRebirth »

CuteAlien wrote:Uh, too long ago - don't remember. But looking at my code I seem to get all my own classes from my own NativeActivity class
(something like public class MyNativeActivity extends android.app.NativeActivity).

So it looks like:

Code: Select all

 
// Get function to get the class  I want. For this to work my NativeActivity has a function:
// public BillingHelper getBillingHelper()
jobject objectActivity = mAndroidApp.activity->clazz;
jclass classActivity = jniEnv->GetObjectClass(objectActivity);
jmethodID methodGetInAppHelper = jniEnv->GetMethodID(classActivity, "getBillingHelper", "()Lcom/irrgheist/hcraft_championship/BillingHelper;");
 
// now call that function to get the class object
jobject objectInAppHelper = jniEnv->CallObjectMethod(objectActivity, methodGetInAppHelper);
jclass classInAppHelper = jniEnv->GetObjectClass(objectInAppHelper);
 
// now can call the method for my own class
jmethodID methodRequestSynchronize = jniEnv->GetMethodID(classInAppHelper, "requestServerConnection", "()V");
jniEnv->CallVoidMethod(objectInAppHelper, methodRequestSynchronize);
 
mAndroidApp is an "android_app" object. And real code has checks after each call (it's in billing_googleplay.cpp in hcraft code if you want to see original code).
Great, that's exactly what I was looking for :-)
I should really use the HCraft source more often.
Thanks

As I try to do the opposite, call a C++ function from Java, I'm getting a strange error

Code: Select all

01-07 00:25:47.196 32476 32476 E zygote  : No implementation found for void com.Game.app.Game.test() (tried Java_com_Game_app_Game_test and Java_com_Game_app_Game_test__)
Here's my C++ code:

Code: Select all

JNIEXPORT void JNICALL Java_com_Game_app_Game_test(JNIEnv* env, jobject thiz)
{
    Game::log("IT WORKED 1!");
}
And the Java code:

Code: Select all

public native void test();
 
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode==123 && resultCode==RESULT_OK) {
        Uri selectedfile = data.getData(); //The uri with the location of the file
        System.out.println("GOT FILE:");
        System.out.println(selectedfile.toString());
        test();
    }   
}
It is printing the file correctly, but crashes when reaching test();

Upon research, it seems possible that I'm not loading the required library in Java with System.loadLibrary(). I would do this, but nowhere states what the library name is. The Java code is in my project's NativeActivity.

Thanks again for your help
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Call Java method from C++

Post by CuteAlien »

I didn't try that one yet. But it makes sense that the c++ code you use has to be in a library so java can call it.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Call Java method from C++

Post by LunaRebirth »

Yeah, it did.

I simply followed this tutorial: https://thebreakfastpost.com/2012/01/21 ... roduction/
and it worked great :)
Post Reply