jni call java method which take a custom java interface as parameter

android, c++, cocos2d-x, java, java-native-interface

Solution

Well firstly you'll need to build a class that can wrap the native C++ function pointer in a TagCallback compatible base class:

public class NativeTagCallback : TagCallback
{
    protected long      cppCallbackPtr;

    public NativeTagCallback( long callbackPtr )
    {
        cppCallbackPtr = callbackPtr;
    }

    public native void NativeCallback( long callbackPtr, int arg0, String arg1, Set<String> arg2 );

    public void callback(int arg0, String arg1, Set<String> arg2) 
    {
        NativeCallback( cppCallbackPtr, arg0, arg2, arg2 );
    }
}

The native code would be defined as follows:

extern "C" jvoid Java_com_wrapper_NativeTagCallback_NativeCallback( JNIEnv* pEnv, jobject jCaller, jlong cppCallbackPtr, jint arg0, jstring arg1, jobject arg2 )
{
    MyCallback cppCallback = (MyCallback)cppCallbackPtr;
    const char* pCString = pEnv->GetStringUTFChars( arg1, 0);
    string arg1Str( pCString );
    pEnv->ReleaseStringUTFChars( arg1, pCString );

    set< string > arg2Set = ConvertJavaSetToCPPSet( arg2 );  // Perform your java to CPP set conversion here.

    cppCallbackPtr( (int)arg0, arg1Str, arg2Set );
}

Then you would create the relevant class and pass it to your function from C++ as follows:

void MyCpp::setTags(set<string> tags, MyCallback callback)
{
    extern __thread JNIEnv* gpEnv;

    // Get the setTags function.
    jclass      jWrapperClass                   = gpEnv->FindClass( "com/wrapper/cocoswrapper" ); // Insert the correct class name here.    
    jmethodID   jWrapperSetTag                  = gpEnv->GetStaticMethodID( jWrapperClass, "setTags", "(Landroid/content/Context;Ljava/util/Set;Lcom/wrapper/TagCallback)V;" );

    // Get the TagCallback related function
    jclass      jNativeTagCallbackClass         = gpEnv->FindClass( "com/wrapper/NativeTagCallback" );
    jclass      jNativeTagCallbackConstructor   = gpEnv->GetMethodID( jNativeTagCallbackClass, "<init>", "(J)V" );
    jobject     jNativeTagCallbackObject        = gpEnv->NewObject( jNativeTagCallbackClass, jNativeTagCallbackConstructor, (jlong)callback)

    // Make function call.
    gpEnv->CallStaticVoidMethod( jWrapperClass, jWrapperSetTag, jAndroidContext, tags.GetJNIObject(), jNativeTagCallbackObject );
}

Problem

I'm working on a plugin project on cocos2d-x platform , I'd like to write some c++ wrapper interface to invoke java method through JNI from `jar` SDK . I know how to use JNI to invoke a static java method, but I'm confused by the interface parameter in the java function. I hava a cpp function pointer to handling callbacks: ``` typedef void (* MyCallback)(int responseCode, string arg1, set<string> arg2); ``` and I want to write a cpp wrapper method like : ``` static void MyCpp::setTags(set<string> tags, MyCallback callback) //it use `JNI` to invoke java method setTags(Context context, Set<String> tags, TagCallback callback). ``` The java method I want to invoke in the wrapper is ``` public static void setTags(Context context, Set<String> tags, TagCallback callback) ``` and the `TagCallback` is an interface for API user to implement. So, is it possible to get `TagCallback` finally callback to `MyCallback` function? in other words , can I use `jni` to convert a cpp function pointer to java interface? Thanks for your patience . EDIT: here is how to use `setTag` if user want to use java only: ``` public static void setTags(context, tags, new TagCallback{ @Override public void callback(int arg0, String arg1, Set<String> arg2) { // TODO Auto-generated method stub } }) ``` I'd like my SDK user to use my cpp wrapper method like this: ``` void setTagCallback(int responseCode, string arg1, set<string> arg2){ //users handle callback themselves. } void someOtherMethodInvokeTheCppWrapperMethod(){ MyCallback callback = setTagCallback; set<string> tags; MyCpp::setTags(tags,callback); } ```

Original source

Related problems