2023-01-20 261
我正在研究Cocos2D-X平台上的一个插件项目,我想编写一些C ++包装器接口,以通过 jni 从jar sdk调用Java方法.我知道如何使用JNI调用静态Java方法,但是我对Java函数中的接口参数感到困惑.
我将CPP功能指针指向处理回调:
typedef void (* MyCallback)(int responseCode, string arg1, set<string> arg2);
我想编写一个CPP包装器方法:
static void MyCpp::setTags(set<string> tags, MyCallback callback) //it use `JNI` to invoke java method setTags(Context context, Set<String> tags, TagCallback callback).
我想在包装器中调用的Java方法是
public static void setTags(Context context, Set<String> tags, TagCallback callback)
和TagCallback是API用户实现的接口.
那么,是否可以最终回到MyCallback函数?换句话说,我可以使用jni将CPP函数指针转换为Java接口吗?
感谢您的耐心配合.
编辑:
如果用户只想使用Java,则是如何使用setTag的方法:
public static void setTags(context, tags, new TagCallback{
@Override
public void callback(int arg0, String arg1, Set<String> arg2) {
// TODO Auto-generated method stub
}
})
我希望我的SDK用户使用我的CPP包装器方法:
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);
}
好吧,首先您需要构建可以将本机C ++功能指针包装在tagCallback兼容基类中的类:
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 );
}
}
本机代码将定义如下:
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 );
}
然后,您将创建相关类,并将其从C ++传递给您的功能:
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 );
}
我会说您需要一个(私有)Java类实现tagCallback,该类可存储C ++功能指针并实现Java-to-C ++回调改编:
private class NativeTagCallback implements TagCallback {
private long _callbackPointer;
private NativeTagCallback(long cb) { _callbackPointer = cb; }
@Override
public native void callback(int arg0, String arg1, Set<String> arg2);
}
在NativeTagCallback.callback()的C ++实现中,您获取并转换参数
从java String和Set<String>对象到本机C ++,然后使用JNI GetFieldID()和GetLongField()函数将传递给您的JNI C ++函数传递的jobject objectOrClass参数从jobject objectOrClass参数中拉出.
拥有_callbackPointer后,您可以将其施放到C ++功能指针并调用.
要使用适配器类,在MyCpp::setTags中,您将使用jni FindClass(),GetMethodID()和NewObject()创建一个NativeTagCallback的实例,将(long)(void *)callback传递给cb cb. (这假设您的编译器生成了可以适合64位的功能指针.对于免费功能指针而言,这通常是正确的 – 与方法指针相对于方法,但值得通过快速测试程序检查.)然后,您将实例到Java setTags()方法为其`callback`参数.
保持NativeTagCallback私有非常重要,因为它可以用于调用任意地址!如果您想变得更加偏执,但很难进行调试,则可以保留C ++ ID到功能的映射,而仅存储NativeTagCallback中的ID. (这将限制可可的地址到当前用于实际回调的地址.ID可以由native void callback()注册,但地图需要是线程安全的.)
这里(我希望我有意义)
我从” cchttprequest”库中获得了这个想法,
在JNI类中,保留回调图.
典型的JNI调用将是(首先是同步的,这是一种非常简单的方法),
void requestForItems(int itemId, CCObject* target, SEL_CallFuncND selector) {
//U can have a small struct/class that contains 2 fields, a CCObject* and a SEL_CallFuncND) i.e, the object and its function
//Give this callback/target object a uniqueId, Add this pair(uniqueId, callbackObject) to the map)
//make sure u retain the "target" so that it stays alive until u call the callback function after the Java call returns
JniMethodInfo t;
if (JniHelper::getStaticMethodInfo(t, "com/myproj/folder/AbcManager", "requestItems",
"(ILjava/lang/String;)Ljava/lang/String;")) {
jstring id = (jstring) t.env->CallStaticObjectMethod(t.classID, t.methodID, itemId, uniqueId);
const char* _data = t.env->GetStringUTFChars (id, 0);
t.env->DeleteLocalRef(t.classID);
//_data >>> is the Id returned, but since we are creating "uniqueId" in this function, this won't be of that importance in a synchronous call
/// call this selector function
if (target && selector) {
(target->*selector)(null, null); //first argument is the sender, the next is a void pointer which u can use to send any information
target->release(); //as we retained it earlier
}
}
}
呼叫者将发送类似>>>的内容,callfuncnd_selector(xyzclass :: accation)
现在,对于异步调用,上述功能将更改为
.
.
.
t.env->CallStaticVoidMethod(t.classID, t.methodID, itemId, uniqueId);
t.env->DeleteLocalRef(t.classID);
}
现在,在此JNI调用的回调函数中,
说方法>>>
JNIEXPORT void JNICALL Java_com_myproj_folder_AbcManager_callingAbcRequestCallback(JNIEnv* env, jobject thiz, jstring data) {
const char * _data = env->GetStringUTFChars (data, 0);
//here we'll do the remaining work
//_data >>> is the Id of the callbackObject
//Get the Object from the Map for thie Id
// call this selector function
if (callbackObject->getTarget() && callbackObject->getSelector()) {
(callbackObject->getTarget()->*callbackObject->getSelector())(null, null);
}
//Now you can delete the object and remove the map entry
}
我们所做的是,我们完成了类,其中包含我们需要调用的功能,实现接口,然后将它们传递给JNI,然后从Java返回时,我们称之为方法,我们将这些对象实现了.
这也可能对您有用,但是您仍然需要将它们保留在地图中,以便您可以识别哪种对象的调用方法.
以上所述是小编给大家介绍的JNI调用Java方法,将自定义Java接口作为参数,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!
原文链接:https://77isp.com/post/26056.html
=========================================
https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。
数据库技术 2022-03-28
网站技术 2022-11-26
网站技术 2023-01-07
网站技术 2022-11-17
Windows相关 2022-02-23
网站技术 2023-01-14
Windows相关 2022-02-16
Windows相关 2022-02-16
Linux相关 2022-02-27
数据库技术 2022-02-20
抠敌 2023年10月23日
嚼餐 2023年10月23日
男忌 2023年10月22日
瓮仆 2023年10月22日
簿偌 2023年10月22日
扫码二维码
获取最新动态